first commit
This commit is contained in:
commit
6e6286dd80
36
.gitignore
vendored
Normal file
36
.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**
|
||||||
|
!**/src/test/**
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
/.mvn/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### lucene ###
|
||||||
|
index
|
||||||
|
userDic
|
0
Dockerfile
Normal file
0
Dockerfile
Normal file
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 RYMCU
|
||||||
|
|
||||||
|
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.
|
105
README.md
Normal file
105
README.md
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# forest
|
||||||
|
![forest](src/main/resources/static/logo_size.jpg)
|
||||||
|
下一代的知识社区系统,为未来而建
|
||||||
|
|
||||||
|
## 💡 简介
|
||||||
|
|
||||||
|
forest([ˈfôrəst],n.森林)是一款现代化的知识社区项目,使用 SpringBoot + Shiro + MyBatis + JWT + Redis 实现。
|
||||||
|
|
||||||
|
与 [nubula](https://github.com/rymcu/nubula) ([ˈnebyələ],n.星云)一起食用,让我们一起探索知识社区的未来。
|
||||||
|
|
||||||
|
[forest 食用手册](UserManual.md)
|
||||||
|
|
||||||
|
## ⚡ 动机
|
||||||
|
|
||||||
|
在 2019 年的某一天,受到 [Hugh](https://rymcu.com/user/RYMCU-J) 的邀请, 构建一个开源嵌入式知识学习交流平台。因此就有了 forest 这个项目。 forest
|
||||||
|
在很多方面受到了 [Symphony](https://github.com/88250/symphony) 的启发,并尝试着在 [Symphony](https://github.com/88250/symphony)
|
||||||
|
和 [B3log 思想](https://ld246.com/article/1546941897596) 的基础上进一步探索。
|
||||||
|
|
||||||
|
## ✨ 特性
|
||||||
|
|
||||||
|
- 内容编辑器
|
||||||
|
- Markdown(GFM)
|
||||||
|
- emoji
|
||||||
|
- 上传文件
|
||||||
|
- 图片
|
||||||
|
- 文件
|
||||||
|
- 单独渲染 MP3 文件
|
||||||
|
- 单独渲染视频文件
|
||||||
|
- 剪切板处理
|
||||||
|
- 粘贴内容处理为 Markdown
|
||||||
|
- 粘贴图片自动重新上传
|
||||||
|
- 数学公式(LaTeX)、流程图支持
|
||||||
|
- 工具栏
|
||||||
|
- 表情
|
||||||
|
- 粗体
|
||||||
|
- 斜体
|
||||||
|
- 引用
|
||||||
|
- 无序列表
|
||||||
|
- 有序列表
|
||||||
|
- 链接
|
||||||
|
- 上传
|
||||||
|
- 预览
|
||||||
|
- 全屏
|
||||||
|
- 编辑模式
|
||||||
|
- 传统的 Markdown 分屏编辑预览
|
||||||
|
- 保留 Markdown 标记符的即时渲染
|
||||||
|
- 类富文本编辑器的所见即所得
|
||||||
|
- 注册
|
||||||
|
- 用户名
|
||||||
|
- 邮箱
|
||||||
|
- 验证码
|
||||||
|
- 登录
|
||||||
|
- 账户(用户名/邮箱)
|
||||||
|
- 密码
|
||||||
|
- 忘记密码
|
||||||
|
- 邮箱
|
||||||
|
- 邮箱验证
|
||||||
|
- 发帖
|
||||||
|
- 帖子类型
|
||||||
|
- 普通帖子
|
||||||
|
- 标题
|
||||||
|
- 正文
|
||||||
|
- 内容编辑器
|
||||||
|
- 标签
|
||||||
|
- 使用已有(选择、自动完成)或创建
|
||||||
|
- 默认“待分类”
|
||||||
|
- 发布后
|
||||||
|
- 可更新
|
||||||
|
- 可删除
|
||||||
|
- 回帖
|
||||||
|
- 内容编辑器
|
||||||
|
- 回复(回复针对回帖)
|
||||||
|
- 货币
|
||||||
|
- 货币规则
|
||||||
|
- 浏览贴子
|
||||||
|
- 编辑自己的帖子
|
||||||
|
- 发布时间/浏览数/标签
|
||||||
|
- 分享
|
||||||
|
- 微信
|
||||||
|
- 分享链接(带用户标识)
|
||||||
|
|
||||||
|
## 报告缺陷
|
||||||
|
|
||||||
|
> 社区系统可能存在一些潜在的缺陷,大家如果有空的话可以帮助我们一起解决。
|
||||||
|
|
||||||
|
如果你在使用社区时发现了如下类型的问题,请回帖进行反馈,并附上 bug 截图以及操作步骤:
|
||||||
|
|
||||||
|
* **功能性缺陷**:例如发布文章失败、创建作品集失败等
|
||||||
|
* **安全性漏洞**:例如 XSS/CSRF、盗用用户信息等
|
||||||
|
|
||||||
|
## 功能建议
|
||||||
|
|
||||||
|
欢迎对社区提出功能特性方面的建议,我们一起讨论,如果有可能我们会尽快实现。
|
||||||
|
|
||||||
|
在提功能建议前可以先看一下 [计划表](https://rymcu.com/article/29) ,避免重复提议
|
||||||
|
|
||||||
|
## 鸣谢
|
||||||
|
- 感谢 `JetBrains` 对本项目的帮助,为作者提供了开源许可版 `JetBrains` 全家桶
|
||||||
|
|
||||||
|
![JetBrains](src/main/resources/static/jb_beam.svg)
|
||||||
|
|
||||||
|
|
||||||
|
## ⭐ Star 历史
|
||||||
|
|
||||||
|
[![Stargazers over time](https://starchart.cc/rymcu/forest.svg)](https://starchart.cc/rymcu/forest)
|
85
UserManual.md
Normal file
85
UserManual.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# forest 食用手册
|
||||||
|
感谢使用 forest,以下是本项目的开发手册
|
||||||
|
## 开发环境搭建
|
||||||
|
### ide
|
||||||
|
本项目使用 `JetBrains IntelliJ IDEA UItimate` 作为编辑器进行开发
|
||||||
|
### java 环境
|
||||||
|
本项目在 `java se 8` 环境下进行开发
|
||||||
|
### 数据库
|
||||||
|
- `redis`
|
||||||
|
- `mysql`
|
||||||
|
## 其他
|
||||||
|
- 本项目使用了 `Lombok`,所以你还需在你的编辑器上安装 `Lombok` 插件
|
||||||
|
- 本项目使用 `maven` 作为依赖管理工具
|
||||||
|
|
||||||
|
## 初始化数据库
|
||||||
|
|
||||||
|
![forest-sql](https://static.rymcu.com/article/1650261394563.png)
|
||||||
|
|
||||||
|
执行 `resources/static` 目录下的 `forest.sql` 文件进行数据库初始化操作
|
||||||
|
|
||||||
|
## 配置文件说明
|
||||||
|
|
||||||
|
### 数据库配置
|
||||||
|
```yaml
|
||||||
|
datasource:
|
||||||
|
url: jdbc:mysql://localhost:3306/forest?characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
|
||||||
|
username: root
|
||||||
|
password: # 数据库密码
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
```
|
||||||
|
|
||||||
|
- `characterEncoding` 指定处理字符的解码和编码的格式
|
||||||
|
- `serverTimezone` 指定时区
|
||||||
|
- `allowMultiQueries` 允许多行 `sql` 一起执行
|
||||||
|
### redis 配置
|
||||||
|
```yaml
|
||||||
|
redis:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 6379
|
||||||
|
password: # redis 密码
|
||||||
|
database: 1
|
||||||
|
timeout: 3000
|
||||||
|
jedis:
|
||||||
|
pool:
|
||||||
|
max-active: 8
|
||||||
|
max-wait: 1
|
||||||
|
max-idle: 500
|
||||||
|
min-idle: 0
|
||||||
|
```
|
||||||
|
### 邮箱服务配置
|
||||||
|
```yaml
|
||||||
|
mail:
|
||||||
|
host: smtp.163.com # 网站发送邮件邮箱服务 host
|
||||||
|
port: 465
|
||||||
|
username: # 邮箱
|
||||||
|
password: # 密码
|
||||||
|
```
|
||||||
|
|
||||||
|
用户注册及找回密码时使用,本项目使用的是网易邮箱,其他邮箱可根据官方教程配置
|
||||||
|
|
||||||
|
### 系统资源路径配置
|
||||||
|
```yaml
|
||||||
|
resource:
|
||||||
|
domain: http://yourdomain.com # 网站域名,本地测试时填写前端项目访问地址即可
|
||||||
|
file-path: http://yourdomain.com # 上传文件前缀域名,本地测试时填写前端项目访问地址即可
|
||||||
|
pic-path: /yoursrc/xx/nebula/static # 上传文件存储地址,本地测试时填写前端项目路径下的 static 目录即可
|
||||||
|
```
|
||||||
|
### 百度相关配置
|
||||||
|
```yaml
|
||||||
|
baidu:
|
||||||
|
data:
|
||||||
|
site: https://yourdomain.com # 百度搜索(SEO)绑定网站域名
|
||||||
|
token: xxxx
|
||||||
|
ai:
|
||||||
|
appId: xxx # 百度AI-文字识别 应用 appId
|
||||||
|
appKey: xxxx # 百度AI-文字识别 应用 appKey
|
||||||
|
secretKey: xxxx # 百度AI-文字识别 应用 secretKey
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
**Q: 找不到数据库配置,Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.**
|
||||||
|
|
||||||
|
A: 检查是否配置了资源文件目录
|
||||||
|
|
||||||
|
![1636569760e18471dd2c74bedac5756e5fff537df.png](https://static.rymcu.com/article/1650261657433.png)
|
179
forest.iml
Normal file
179
forest.iml
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<?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>
|
||||||
|
<root url="file://$MODULE_DIR$/src/main/webapp" relative="/" />
|
||||||
|
</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/test/java" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||||
|
<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-data-redis:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.9.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.79.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.79.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.79.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.79.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-unix-common:4.1.79.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.79.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.79.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.21" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.32" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-mail:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.sun.mail:jakarta.mail:1.6.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.7" level="project" />
|
||||||
|
<orderEntry type="library" scope="RUNTIME" name="Maven: mysql:mysql-connector-java:8.0.30" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.24" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.65" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.65" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.65" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.7.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.22.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:4.5.1" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy:1.12.12" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.12.12" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:3.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:4.5.1" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.9.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: net.minidev:json-smart:2.4.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: net.minidev:accessors-smart:2.4.8" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.ow2.asm:asm:9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: tk.mybatis:mapper:4.2.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: javax.persistence:persistence-api:1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:4.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.alibaba:fastjson:2.0.14" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2-extension:2.0.14" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.14" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-spring:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-lang:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-cache:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-hash:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-core:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-cipher:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-core:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-ogdl:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.9.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-event:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-web:1.9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.owasp.encoder:encoder:1.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: commons-io:commons-io:2.11.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" 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.13.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.2.13-SNSAPSHOT" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.alibaba:druid:1.2.13-SNSAPSHOT" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.19.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.19.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-configuration-processor:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-thymeleaf:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf-spring5:3.0.15.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf:3.0.15.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.attoparser:attoparser:2.0.5.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.unbescape:unbescape:1.1.6.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-websocket:2.7.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-messaging:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-websocket:5.3.22" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.jodd:jodd-http:6.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.jodd:jodd-util:6.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.jedis-lock:jedis-lock:1.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: redis.clients:jedis:3.8.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.11.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-queryparser:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-core:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-queries:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-sandbox:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-analyzers-common:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-highlighter:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-memory:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.lucene:lucene-suggest:8.11.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: cn.hutool:hutool-core:5.8.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: cn.hutool:hutool-http:5.8.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.warrenstrange:googleauth:1.5.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.15" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
322
mvnw
vendored
Normal file
322
mvnw
vendored
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
#!/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
|
||||||
|
))"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
javaExecutable="$(which javac)"
|
||||||
|
if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then
|
||||||
|
# readlink(1) is not available as standard on Solaris 10.
|
||||||
|
readLink=$(which readlink)
|
||||||
|
if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then
|
||||||
|
if $darwin; then
|
||||||
|
javaHome="$(dirname \"$javaExecutable\")"
|
||||||
|
javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac"
|
||||||
|
else
|
||||||
|
javaExecutable="$(readlink -f \"$javaExecutable\")"
|
||||||
|
fi
|
||||||
|
javaHome="$(dirname \"$javaExecutable\")"
|
||||||
|
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||||
|
JAVA_HOME="$javaHome"
|
||||||
|
export JAVA_HOME
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVACMD" ]; then
|
||||||
|
if [ -n "$JAVA_HOME" ]; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(which java)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ]; then
|
||||||
|
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||||
|
echo " We cannot execute $JAVACMD" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
echo "Warning: JAVA_HOME environment variable is not set."
|
||||||
|
fi
|
||||||
|
|
||||||
|
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||||
|
|
||||||
|
# traverses directory structure from process work directory to filesystem root
|
||||||
|
# first directory with .mvn subdirectory is considered project base directory
|
||||||
|
find_maven_basedir() {
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Path not specified to find_maven_basedir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
basedir="$1"
|
||||||
|
wdir="$1"
|
||||||
|
while [ "$wdir" != '/' ]; do
|
||||||
|
if [ -d "$wdir"/.mvn ]; then
|
||||||
|
basedir=$wdir
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||||
|
if [ -d "${wdir}" ]; then
|
||||||
|
wdir=$(
|
||||||
|
cd "$wdir/.."
|
||||||
|
pwd
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
# end of workaround
|
||||||
|
done
|
||||||
|
echo "${basedir}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# concatenates all lines of a file
|
||||||
|
concat_lines() {
|
||||||
|
if [ -f "$1" ]; then
|
||||||
|
echo "$(tr -s '\n' ' ' <"$1")"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
BASE_DIR=$(find_maven_basedir "$(pwd)")
|
||||||
|
if [ -z "$BASE_DIR" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
##########################################################################################
|
||||||
|
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||||
|
fi
|
||||||
|
if [ -n "$MVNW_REPOURL" ]; then
|
||||||
|
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||||
|
else
|
||||||
|
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||||
|
fi
|
||||||
|
while IFS="=" read key value; do
|
||||||
|
case "$key" in wrapperUrl)
|
||||||
|
jarUrl="$value"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done <"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Downloading from: $jarUrl"
|
||||||
|
fi
|
||||||
|
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||||
|
if $cygwin; then
|
||||||
|
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v wget >/dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found wget ... using wget"
|
||||||
|
fi
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
wget "$jarUrl" -O "$wrapperJarPath"
|
||||||
|
else
|
||||||
|
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||||
|
fi
|
||||||
|
elif command -v curl >/dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found curl ... using curl"
|
||||||
|
fi
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||||
|
else
|
||||||
|
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Falling back to using Java to download"
|
||||||
|
fi
|
||||||
|
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||||
|
# For Cygwin, switch paths to Windows format before running javac
|
||||||
|
if $cygwin; then
|
||||||
|
javaClass=$(cygpath --path --windows "$javaClass")
|
||||||
|
fi
|
||||||
|
if [ -e "$javaClass" ]; then
|
||||||
|
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
# Compiling the Java class
|
||||||
|
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||||
|
fi
|
||||||
|
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
# Running the downloader
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Running MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
##########################################################################################
|
||||||
|
# End of extension
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo $MAVEN_PROJECTBASEDIR
|
||||||
|
fi
|
||||||
|
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME=$(cygpath --path --windows "$M2_HOME")
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||||
|
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||||
|
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Provide a "standardized" way to retrieve the CLI args that will
|
||||||
|
# work with both Windows and non-Windows executions.
|
||||||
|
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||||
|
export MAVEN_CMD_LINE_ARGS
|
||||||
|
|
||||||
|
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
exec "$JAVACMD" \
|
||||||
|
$MAVEN_OPTS \
|
||||||
|
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||||
|
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||||
|
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
182
mvnw.cmd
vendored
Normal file
182
mvnw.cmd
vendored
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM 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 by setting MAVEN_BATCH_ECHO to 'on'
|
||||||
|
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||||
|
|
||||||
|
@REM set %HOME% to equivalent of $HOME
|
||||||
|
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||||
|
|
||||||
|
@REM Execute a user defined script before this one
|
||||||
|
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||||
|
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||||
|
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||||
|
:skipRcPre
|
||||||
|
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
set ERROR_CODE=0
|
||||||
|
|
||||||
|
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
@REM ==== START VALIDATION ====
|
||||||
|
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME not found in your environment. >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
:OkJHome
|
||||||
|
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||||
|
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
@REM ==== END VALIDATION ====
|
||||||
|
|
||||||
|
:init
|
||||||
|
|
||||||
|
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||||
|
@REM Fallback to current working directory if not found.
|
||||||
|
|
||||||
|
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||||
|
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||||
|
|
||||||
|
set EXEC_DIR=%CD%
|
||||||
|
set WDIR=%EXEC_DIR%
|
||||||
|
:findBaseDir
|
||||||
|
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||||
|
cd ..
|
||||||
|
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||||
|
set WDIR=%CD%
|
||||||
|
goto findBaseDir
|
||||||
|
|
||||||
|
:baseDirFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
goto endDetectBaseDir
|
||||||
|
|
||||||
|
:baseDirNotFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
|
||||||
|
:endDetectBaseDir
|
||||||
|
|
||||||
|
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||||
|
|
||||||
|
@setlocal EnableExtensions EnableDelayedExpansion
|
||||||
|
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||||
|
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||||
|
|
||||||
|
:endReadAdditionalConfig
|
||||||
|
|
||||||
|
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||||
|
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||||
|
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||||
|
|
||||||
|
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||||
|
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||||
|
)
|
||||||
|
|
||||||
|
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
if exist %WRAPPER_JAR% (
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Found %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
if not "%MVNW_REPOURL%" == "" (
|
||||||
|
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
|
||||||
|
)
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||||
|
echo Downloading from: %DOWNLOAD_URL%
|
||||||
|
)
|
||||||
|
|
||||||
|
powershell -Command "&{"^
|
||||||
|
"$webclient = new-object System.Net.WebClient;"^
|
||||||
|
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||||
|
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||||
|
"}"^
|
||||||
|
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||||
|
"}"
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Finished downloading %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@REM End of extension
|
||||||
|
|
||||||
|
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||||
|
@REM work with both Windows and non-Windows executions.
|
||||||
|
set MAVEN_CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||||
|
if ERRORLEVEL 1 goto error
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:error
|
||||||
|
set ERROR_CODE=1
|
||||||
|
|
||||||
|
:end
|
||||||
|
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||||
|
|
||||||
|
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||||
|
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||||
|
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||||
|
:skipRcPost
|
||||||
|
|
||||||
|
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||||
|
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||||
|
|
||||||
|
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||||
|
|
||||||
|
exit /B %ERROR_CODE%
|
286
pom.xml
Normal file
286
pom.xml
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.7.2</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.rymcu</groupId>
|
||||||
|
<artifactId>forest</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<name>forest</name>
|
||||||
|
<description>forest(森林) —— 一款现代化的知识社区后台项目,使用 SpringBoot + Shrio + MyBatis + JWT + Redis 实现。</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<lucene.version>8.11.2</lucene.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-to-slf4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.yaml</groupId>
|
||||||
|
<artifactId>snakeyaml</artifactId>
|
||||||
|
<version>1.32</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis.spring.boot</groupId>
|
||||||
|
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||||
|
<version>2.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>8.0.30</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.vaadin.external.google</groupId>
|
||||||
|
<artifactId>android-json</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>net.minidev</groupId>
|
||||||
|
<artifactId>json-smart</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/net.minidev/json-smart -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.minidev</groupId>
|
||||||
|
<artifactId>json-smart</artifactId>
|
||||||
|
<version>2.4.8</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- 通用Mapper插件 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>tk.mybatis</groupId>
|
||||||
|
<artifactId>mapper</artifactId>
|
||||||
|
<version>4.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- pagehelper -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.pagehelper</groupId>
|
||||||
|
<artifactId>pagehelper</artifactId>
|
||||||
|
<version>5.3.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- fastjson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>2.0.14</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- shiro权限控制框架 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-spring</artifactId>
|
||||||
|
<version>1.9.1</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-collections</groupId>
|
||||||
|
<artifactId>commons-collections</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!--apache相关依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-lang</groupId>
|
||||||
|
<artifactId>commons-lang</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.11.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-text</artifactId>
|
||||||
|
<version>1.9</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.15</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt</artifactId>
|
||||||
|
<version>0.9.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 阿里巴巴连接池Druid -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
<version>1.2.13-SNSAPSHOT</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-to-slf4j</artifactId>
|
||||||
|
<version>2.19.0</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<version>2.19.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jodd</groupId>
|
||||||
|
<artifactId>jodd-http</artifactId>
|
||||||
|
<version>6.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jedis-lock</groupId>
|
||||||
|
<artifactId>jedis-lock</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- lucene -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.lucene</groupId>
|
||||||
|
<artifactId>lucene-queryparser</artifactId>
|
||||||
|
<version>${lucene.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.lucene</groupId>
|
||||||
|
<artifactId>lucene-analyzers-common</artifactId>
|
||||||
|
<version>${lucene.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.lucene</groupId>
|
||||||
|
<artifactId>lucene-highlighter</artifactId>
|
||||||
|
<version>${lucene.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.lucene</groupId>
|
||||||
|
<artifactId>lucene-suggest</artifactId>
|
||||||
|
<version>${lucene.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- hutool 核心工具包 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-core</artifactId>
|
||||||
|
<version>5.8.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-http</artifactId>
|
||||||
|
<version>5.8.7</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.warrenstrange</groupId>
|
||||||
|
<artifactId>googleauth</artifactId>
|
||||||
|
<version>1.5.0</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<!-- 程序编译时默认不会把 src/main/java 目录下文件添加到 jar 包中,需手动添加 -->
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/java</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**/*.xml</include>
|
||||||
|
<include>**/**/*.xml</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<version>2.3.5.RELEASE</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<finalName>forest</finalName>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
18
src/main/java/com/rymcu/forest/ForestApplication.java
Normal file
18
src/main/java/com/rymcu/forest/ForestApplication.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package com.rymcu.forest;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@EnableAsync
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ForestApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ForestApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/main/java/com/rymcu/forest/ServletInitializer.java
Normal file
13
src/main/java/com/rymcu/forest/ServletInitializer.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.rymcu.forest;
|
||||||
|
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||||
|
|
||||||
|
public class ServletInitializer extends SpringBootServletInitializer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||||
|
return application.sources(ForestApplication.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/main/java/com/rymcu/forest/answer/AnswerController.java
Normal file
50
src/main/java/com/rymcu/forest/answer/AnswerController.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package com.rymcu.forest.answer;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
|
import com.rymcu.forest.core.service.log.annotation.TransactionLogger;
|
||||||
|
import com.rymcu.forest.dto.AnswerDTO;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
|
import com.rymcu.forest.util.HttpUtils;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/answer")
|
||||||
|
public class AnswerController {
|
||||||
|
|
||||||
|
private final static String ANSWER_API_URL = "http://1.116.175.112:8089/question";
|
||||||
|
|
||||||
|
@GetMapping("/today")
|
||||||
|
public GlobalResult today() throws BaseApiException {
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
String result = HttpUtils.sendGet(ANSWER_API_URL + "/record/" + user.getIdUser() );
|
||||||
|
return JSONObject.parseObject(result, GlobalResult.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/answer")
|
||||||
|
@TransactionLogger(transactionType = TransactionEnum.Answer)
|
||||||
|
public GlobalResult answer(@RequestBody AnswerDTO answerDTO) throws BaseApiException {
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
Map params = new HashMap<>(3);
|
||||||
|
params.put("userId", user.getIdUser());
|
||||||
|
params.put("answer", answerDTO.getAnswer());
|
||||||
|
params.put("subjectQuestionId", answerDTO.getIdSubjectQuestion());
|
||||||
|
String result = HttpUtils.sendPost(ANSWER_API_URL + "/answer/everyday", params);
|
||||||
|
return JSONObject.parseObject(result, GlobalResult.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-answer")
|
||||||
|
public GlobalResult getAnswer(Integer idSubjectQuestion) {
|
||||||
|
String result = HttpUtils.sendGet(ANSWER_API_URL + "/show-answer/" + idSubjectQuestion );
|
||||||
|
return JSONObject.parseObject(result, GlobalResult.class);
|
||||||
|
}
|
||||||
|
}
|
153
src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java
Normal file
153
src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
|
||||||
|
import com.rymcu.forest.core.exception.BusinessException;
|
||||||
|
import com.rymcu.forest.core.exception.ServiceException;
|
||||||
|
import com.rymcu.forest.core.exception.TransactionException;
|
||||||
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
|
import com.rymcu.forest.core.result.ResultCode;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionCode;
|
||||||
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.authz.UnauthenticatedException;
|
||||||
|
import org.apache.shiro.authz.UnauthorizedException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理器
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class BaseExceptionHandler {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||||
|
if (isAjax(request)) {
|
||||||
|
GlobalResult result = new GlobalResult();
|
||||||
|
if (ex instanceof BaseApiException) {
|
||||||
|
result.setCode(((BaseApiException) ex).getCode());
|
||||||
|
result.setMessage(((BaseApiException) ex).getExtraMessage());
|
||||||
|
logger.info(result.getMessage());
|
||||||
|
} else if (ex instanceof UnauthenticatedException) {
|
||||||
|
result.setCode(1000001);
|
||||||
|
result.setMessage("token错误");
|
||||||
|
logger.info("token错误");
|
||||||
|
} else if (ex instanceof UnauthorizedException) {
|
||||||
|
result.setCode(1000002);
|
||||||
|
result.setMessage("用户无权限");
|
||||||
|
logger.info("用户无权限");
|
||||||
|
} else if (ex instanceof ServiceException) {
|
||||||
|
//业务失败的异常,如“账号或密码错误”
|
||||||
|
result.setCode(((ServiceException) ex).getCode());
|
||||||
|
result.setMessage(ex.getMessage());
|
||||||
|
logger.info(ex.getMessage());
|
||||||
|
} else if (ex instanceof NoHandlerFoundException) {
|
||||||
|
result.setCode(ResultCode.NOT_FOUND.getCode());
|
||||||
|
result.setMessage(ResultCode.NOT_FOUND.getMessage());
|
||||||
|
} else if (ex instanceof ServletException) {
|
||||||
|
result.setCode(ResultCode.FAIL.getCode());
|
||||||
|
result.setMessage(ex.getMessage());
|
||||||
|
} else if (ex instanceof BusinessException) {
|
||||||
|
result.setCode(ResultCode.FAIL.getCode());
|
||||||
|
result.setMessage(ex.getMessage());
|
||||||
|
} else if (ex instanceof TransactionException) {
|
||||||
|
result.setCode(TransactionCode.InsufficientBalance.getCode());
|
||||||
|
result.setMessage(ex.getMessage());
|
||||||
|
} else {
|
||||||
|
//系统内部异常,不返回给客户端,内部记录错误日志
|
||||||
|
result.setCode(ResultCode.INTERNAL_SERVER_ERROR.getCode());
|
||||||
|
String message;
|
||||||
|
if (handler instanceof HandlerMethod) {
|
||||||
|
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||||
|
message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s",
|
||||||
|
request.getRequestURI(),
|
||||||
|
handlerMethod.getBean().getClass().getName(),
|
||||||
|
handlerMethod.getMethod().getName(),
|
||||||
|
ex.getMessage());
|
||||||
|
} else {
|
||||||
|
message = ex.getMessage();
|
||||||
|
}
|
||||||
|
result.setMessage("操作失败");
|
||||||
|
logger.error(message, ex);
|
||||||
|
}
|
||||||
|
result.setSuccess(false);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
ModelAndView mv = new ModelAndView();
|
||||||
|
FastJsonJsonView view = new FastJsonJsonView();
|
||||||
|
Map<String, Object> attributes = new HashMap(2);
|
||||||
|
if (ex instanceof BaseApiException) {
|
||||||
|
attributes.put("code", ((BaseApiException) ex).getCode());
|
||||||
|
attributes.put("message", ((BaseApiException) ex).getExtraMessage());
|
||||||
|
} else if (ex instanceof UnauthenticatedException) {
|
||||||
|
attributes.put("code", "1000001");
|
||||||
|
attributes.put("message", "token错误");
|
||||||
|
} else if (ex instanceof UnauthorizedException) {
|
||||||
|
attributes.put("code", "1000002");
|
||||||
|
attributes.put("message", "用户无权限");
|
||||||
|
} else if (ex instanceof ServiceException) {
|
||||||
|
//业务失败的异常,如“账号或密码错误”
|
||||||
|
attributes.put("code", ((ServiceException) ex).getCode());
|
||||||
|
attributes.put("message", ex.getMessage());
|
||||||
|
logger.info(ex.getMessage());
|
||||||
|
} else if (ex instanceof NoHandlerFoundException) {
|
||||||
|
attributes.put("code", ResultCode.NOT_FOUND.getCode());
|
||||||
|
attributes.put("message", ResultCode.NOT_FOUND.getMessage());
|
||||||
|
} else if (ex instanceof ServletException) {
|
||||||
|
attributes.put("code", ResultCode.FAIL.getCode());
|
||||||
|
attributes.put("message", ex.getMessage());
|
||||||
|
} else if (ex instanceof BusinessException) {
|
||||||
|
attributes.put("code", ResultCode.FAIL.getCode());
|
||||||
|
attributes.put("message", ex.getMessage());
|
||||||
|
} else if (ex instanceof TransactionException) {
|
||||||
|
attributes.put("code", TransactionCode.InsufficientBalance.getCode());
|
||||||
|
attributes.put("message", ex.getMessage());
|
||||||
|
} else {
|
||||||
|
//系统内部异常,不返回给客户端,内部记录错误日志
|
||||||
|
attributes.put("code", ResultCode.INTERNAL_SERVER_ERROR.getCode());
|
||||||
|
String message;
|
||||||
|
if (handler instanceof HandlerMethod) {
|
||||||
|
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||||
|
message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s",
|
||||||
|
request.getRequestURI(),
|
||||||
|
handlerMethod.getBean().getClass().getName(),
|
||||||
|
handlerMethod.getMethod().getName(),
|
||||||
|
ex.getMessage());
|
||||||
|
} else {
|
||||||
|
message = ex.getMessage();
|
||||||
|
}
|
||||||
|
logger.error(message, ex);
|
||||||
|
attributes.put("message", "操作失败");
|
||||||
|
}
|
||||||
|
attributes.put("success", false);
|
||||||
|
view.setAttributesMap(attributes);
|
||||||
|
mv.setView(view);
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAjax(HttpServletRequest request) {
|
||||||
|
String requestedWith = request.getHeader("x-requested-with");
|
||||||
|
if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String contentType = request.getContentType();
|
||||||
|
return StringUtils.isNotBlank(contentType) && contentType.contains("application/json");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
|
||||||
|
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
|
||||||
|
import org.apache.shiro.web.util.WebUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class BaseSessionManager extends DefaultWebSessionManager {
|
||||||
|
private static final String AUTHORIZATION = "Authorization";
|
||||||
|
|
||||||
|
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
|
||||||
|
|
||||||
|
public BaseSessionManager() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
|
||||||
|
String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
|
||||||
|
// 如果请求头中有 Authorization 则其值为 sessionId
|
||||||
|
if (!StringUtils.isEmpty(id)) {
|
||||||
|
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
|
||||||
|
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
|
||||||
|
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
} else {
|
||||||
|
// 否则按默认规则从 cookie 取 sessionId
|
||||||
|
return super.getSessionId(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import org.apache.shiro.mgt.SecurityManager;
|
||||||
|
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||||
|
import org.apache.shiro.web.filter.mgt.FilterChainManager;
|
||||||
|
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
|
||||||
|
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
|
||||||
|
import org.apache.shiro.web.mgt.WebSecurityManager;
|
||||||
|
import org.apache.shiro.web.servlet.AbstractShiroFilter;
|
||||||
|
import org.springframework.beans.factory.BeanInitializationException;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
* Shiro静态资源配置
|
||||||
|
* */
|
||||||
|
public class BaseShiroFilterFactoryBean extends ShiroFilterFactoryBean {
|
||||||
|
|
||||||
|
private Set<String> ignoreExt;
|
||||||
|
|
||||||
|
public BaseShiroFilterFactoryBean() {
|
||||||
|
super();
|
||||||
|
ignoreExt = new HashSet<>();
|
||||||
|
ignoreExt.add(".svg");
|
||||||
|
ignoreExt.add(".jpg");
|
||||||
|
ignoreExt.add(".png");
|
||||||
|
ignoreExt.add(".gif");
|
||||||
|
ignoreExt.add(".bmp");
|
||||||
|
ignoreExt.add(".js");
|
||||||
|
ignoreExt.add(".css");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbstractShiroFilter createInstance() throws Exception {
|
||||||
|
|
||||||
|
SecurityManager securityManager = getSecurityManager();
|
||||||
|
if (securityManager == null) {
|
||||||
|
String msg = "SecurityManager property must be set.";
|
||||||
|
throw new BeanInitializationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(securityManager instanceof WebSecurityManager)) {
|
||||||
|
String msg = "The security manager does not implement the WebSecurityManager interface.";
|
||||||
|
throw new BeanInitializationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterChainManager manager = createFilterChainManager();
|
||||||
|
|
||||||
|
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
|
||||||
|
chainResolver.setFilterChainManager(manager);
|
||||||
|
|
||||||
|
return new BaseSpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class BaseSpringShiroFilter extends AbstractShiroFilter {
|
||||||
|
|
||||||
|
protected BaseSpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
|
||||||
|
super();
|
||||||
|
if (webSecurityManager == null) {
|
||||||
|
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
|
||||||
|
}
|
||||||
|
setSecurityManager(webSecurityManager);
|
||||||
|
if (resolver != null) {
|
||||||
|
setFilterChainResolver(resolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
|
||||||
|
FilterChain chain) throws ServletException, IOException {
|
||||||
|
HttpServletRequest request = (HttpServletRequest)servletRequest;
|
||||||
|
String str = request.getRequestURI().toLowerCase();
|
||||||
|
// 因为ShiroFilter 拦截所有请求(在上面我们配置了urlPattern 为 * ,当然你也可以在那里精确的添加要处理的路径,这样就不需要这个类了),而在每次请求里面都做了session的读取和更新访问时间等操作,这样在集群部署session共享的情况下,数量级的加大了处理量负载。
|
||||||
|
// 所以我们这里将一些能忽略的请求忽略掉。
|
||||||
|
// 当然如果你的集群系统使用了动静分离处理,静态资料的请求不会到Filter这个层面,便可以忽略。
|
||||||
|
boolean flag = true;
|
||||||
|
int idx = 0;
|
||||||
|
if(( idx = str.indexOf(".")) > 0){
|
||||||
|
str = str.substring(idx);
|
||||||
|
if(ignoreExt.contains(str.toLowerCase())) {
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(flag){
|
||||||
|
super.doFilterInternal(servletRequest, servletResponse, chain);
|
||||||
|
}else{
|
||||||
|
chain.doFilter(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
158
src/main/java/com/rymcu/forest/config/BaseShiroRealm.java
Normal file
158
src/main/java/com/rymcu/forest/config/BaseShiroRealm.java
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.rymcu.forest.core.constant.ShiroConstants;
|
||||||
|
import com.rymcu.forest.core.exception.CaptchaException;
|
||||||
|
import com.rymcu.forest.entity.Permission;
|
||||||
|
import com.rymcu.forest.entity.Role;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.service.PermissionService;
|
||||||
|
import com.rymcu.forest.service.RoleService;
|
||||||
|
import com.rymcu.forest.service.UserService;
|
||||||
|
import com.rymcu.forest.util.Encodes;
|
||||||
|
import com.rymcu.forest.util.Utils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.ibatis.exceptions.TooManyResultsException;
|
||||||
|
import org.apache.shiro.authc.*;
|
||||||
|
import org.apache.shiro.authz.AuthorizationInfo;
|
||||||
|
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||||
|
import org.apache.shiro.realm.AuthorizingRealm;
|
||||||
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
|
import org.apache.shiro.util.ByteSource;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
* @since 2018/05/28 11:00
|
||||||
|
* 自定义权限匹配和账号密码匹配
|
||||||
|
*/
|
||||||
|
public class BaseShiroRealm extends AuthorizingRealm {
|
||||||
|
@Resource
|
||||||
|
private RoleService roleService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PermissionService permissionService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||||
|
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
|
||||||
|
Principal principal = (Principal) principals.getPrimaryPrincipal();
|
||||||
|
User user = new User();
|
||||||
|
user.setIdUser(principal.getId());
|
||||||
|
try {
|
||||||
|
List<Role> roles = roleService.selectRoleByUser(user);
|
||||||
|
for (Role role : roles) {
|
||||||
|
if (StringUtils.isNotBlank(role.getInputCode())) {
|
||||||
|
authorizationInfo.addRole(role.getInputCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<Permission> permissions = permissionService.selectPermissionByUser(user);
|
||||||
|
for (Permission perm : permissions) {
|
||||||
|
if (perm.getPermissionCategory() != null) {
|
||||||
|
authorizationInfo.addStringPermission(perm.getPermissionCategory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 添加用户权限
|
||||||
|
authorizationInfo.addStringPermission("user");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return authorizationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证回调函数, 登录时调用,主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
|
||||||
|
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
|
||||||
|
//获取用户的输入的账号.
|
||||||
|
String username = token.getUsername();
|
||||||
|
|
||||||
|
User user = null;
|
||||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
if (!org.springframework.util.StringUtils.isEmpty(attributes.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) {
|
||||||
|
throw new CaptchaException();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
user = userService.findByAccount(username);
|
||||||
|
} catch (TooManyResultsException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (user == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 账户冻结(是否允许登陆)
|
||||||
|
if (!"0".equals(user.getStatus())) {
|
||||||
|
throw new LockedAccountException();
|
||||||
|
}
|
||||||
|
byte[] salt = Encodes.decodeHex(user.getPassword().substring(0, 16));
|
||||||
|
return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()),
|
||||||
|
user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权用户信息
|
||||||
|
*/
|
||||||
|
public static class Principal implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long id; // 编号
|
||||||
|
private String account; // 登录名
|
||||||
|
private String name; // 姓名
|
||||||
|
private boolean mobileLogin; // 是否手机登录
|
||||||
|
|
||||||
|
// private Map<String, Object> cacheMap;
|
||||||
|
|
||||||
|
public Principal(User user, boolean mobileLogin) {
|
||||||
|
this.id = user.getIdUser();
|
||||||
|
this.account = user.getAccount();
|
||||||
|
this.name = user.getNickname();
|
||||||
|
this.mobileLogin = mobileLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccount() {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMobileLogin() {
|
||||||
|
return mobileLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取SESSIONID
|
||||||
|
*/
|
||||||
|
public String getSessionid() {
|
||||||
|
try {
|
||||||
|
return (String) Utils.getSession().getId();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return id.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
69
src/main/java/com/rymcu/forest/config/MybatisConfigurer.java
Normal file
69
src/main/java/com/rymcu/forest/config/MybatisConfigurer.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import com.github.pagehelper.PageInterceptor;
|
||||||
|
import org.apache.ibatis.plugin.Interceptor;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
|
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static com.rymcu.forest.core.constant.ProjectConstant.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mybatis & Mapper & PageHelper 配置
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class MybatisConfigurer {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
|
||||||
|
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
|
||||||
|
factory.setDataSource(dataSource);
|
||||||
|
factory.setTypeAliasesPackage(MODEL_PACKAGE);
|
||||||
|
|
||||||
|
//配置分页插件,详情请查阅官方文档
|
||||||
|
PageInterceptor pageHelper = new PageInterceptor();
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty("helperDialect", "mysql");
|
||||||
|
properties.setProperty("pageSizeZero", "true");
|
||||||
|
properties.setProperty("reasonable", "true");
|
||||||
|
properties.setProperty("supportMethodsArguments", "true");
|
||||||
|
properties.setProperty("rowBoundsWithCount", "true");
|
||||||
|
pageHelper.setProperties(properties);
|
||||||
|
|
||||||
|
//添加插件
|
||||||
|
factory.setPlugins(pageHelper);
|
||||||
|
|
||||||
|
//添加XML目录
|
||||||
|
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||||
|
factory.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
|
||||||
|
return factory.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MapperScannerConfigurer mapperScannerConfigurer() {
|
||||||
|
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
|
||||||
|
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
|
||||||
|
mapperScannerConfigurer.setBasePackage(MAPPER_PACKAGE);
|
||||||
|
|
||||||
|
//配置通用Mapper,详情请查阅官方文档
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty("mappers", MAPPER_INTERFACE_REFERENCE);
|
||||||
|
properties.setProperty("notEmpty", "false");
|
||||||
|
properties.setProperty("IDENTITY", "JDBC");
|
||||||
|
mapperScannerConfigurer.setProperties(properties);
|
||||||
|
|
||||||
|
|
||||||
|
return mapperScannerConfigurer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.jwt.def.JwtConstants;
|
||||||
|
import com.rymcu.forest.service.UserService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.connection.Message;
|
||||||
|
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2021/10/9 9:25.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
* @packageName com.rymcu.forest.config
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
|
||||||
|
super(listenerContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 针对 redis 数据失效事件,进行数据处理
|
||||||
|
*
|
||||||
|
* @param message key
|
||||||
|
* @param pattern pattern
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onMessage(Message message, byte[] pattern) {
|
||||||
|
|
||||||
|
// 获取到失效的 key
|
||||||
|
String expiredKey = message.toString();
|
||||||
|
if (expiredKey.contains(JwtConstants.LAST_ONLINE)) {
|
||||||
|
String email = expiredKey.replace(JwtConstants.LAST_ONLINE, "");
|
||||||
|
log.info("拿到过期的数据:{}", expiredKey);
|
||||||
|
log.info("处理后的数据:{}", email);
|
||||||
|
userService.updateLastOnlineTimeByEmail(email);
|
||||||
|
}
|
||||||
|
super.onMessage(message, pattern);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2021/10/9 9:23.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
* @packageName com.rymcu.forest.config
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RedisListenerConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
|
||||||
|
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
|
||||||
|
container.setConnectionFactory(connectionFactory);
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
124
src/main/java/com/rymcu/forest/config/RedisProperties.java
Normal file
124
src/main/java/com/rymcu/forest/config/RedisProperties.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import redis.clients.jedis.JedisPoolConfig;
|
||||||
|
import redis.clients.jedis.Protocol;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.SSLParameters;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="https://github.com/007gzs">007</a>
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = "spring.redis")
|
||||||
|
public class RedisProperties extends JedisPoolConfig {
|
||||||
|
private String host = Protocol.DEFAULT_HOST;
|
||||||
|
private int port = Protocol.DEFAULT_PORT;
|
||||||
|
private String password;
|
||||||
|
private int database = 1;
|
||||||
|
private int connectionTimeout = Protocol.DEFAULT_TIMEOUT;
|
||||||
|
private int soTimeout = Protocol.DEFAULT_TIMEOUT;
|
||||||
|
private String clientName;
|
||||||
|
private boolean ssl;
|
||||||
|
private SSLSocketFactory sslSocketFactory;
|
||||||
|
private SSLParameters sslParameters;
|
||||||
|
private HostnameVerifier hostnameVerifier;
|
||||||
|
|
||||||
|
public boolean isSsl() {
|
||||||
|
return ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSsl(boolean ssl) {
|
||||||
|
this.ssl = ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSLSocketFactory getSslSocketFactory() {
|
||||||
|
return sslSocketFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||||
|
this.sslSocketFactory = sslSocketFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSLParameters getSslParameters() {
|
||||||
|
return sslParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSslParameters(SSLParameters sslParameters) {
|
||||||
|
this.sslParameters = sslParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HostnameVerifier getHostnameVerifier() {
|
||||||
|
return hostnameVerifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
|
||||||
|
this.hostnameVerifier = hostnameVerifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
if (host == null || "".equals(host)) {
|
||||||
|
host = Protocol.DEFAULT_HOST;
|
||||||
|
}
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
if ("".equals(password)) {
|
||||||
|
password = null;
|
||||||
|
}
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDatabase() {
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatabase(int database) {
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientName() {
|
||||||
|
return clientName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientName(String clientName) {
|
||||||
|
if ("".equals(clientName)) {
|
||||||
|
clientName = null;
|
||||||
|
}
|
||||||
|
this.clientName = clientName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConnectionTimeout() {
|
||||||
|
return connectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnectionTimeout(int connectionTimeout) {
|
||||||
|
this.connectionTimeout = connectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSoTimeout() {
|
||||||
|
return soTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoTimeout(int soTimeout) {
|
||||||
|
this.soTimeout = soTimeout;
|
||||||
|
}
|
||||||
|
}
|
172
src/main/java/com/rymcu/forest/config/ShiroConfig.java
Normal file
172
src/main/java/com/rymcu/forest/config/ShiroConfig.java
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
|
||||||
|
import org.apache.shiro.mgt.SecurityManager;
|
||||||
|
import org.apache.shiro.session.mgt.SessionManager;
|
||||||
|
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
|
||||||
|
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||||
|
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||||
|
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||||
|
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
|
||||||
|
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.EnvironmentAware;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "redis.shiro")
|
||||||
|
public class ShiroConfig implements EnvironmentAware {
|
||||||
|
|
||||||
|
private Environment env;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnvironment(Environment environment) {
|
||||||
|
this.env=environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
|
||||||
|
ShiroFilterFactoryBean shiroFilterFactoryBean = new BaseShiroFilterFactoryBean();
|
||||||
|
shiroFilterFactoryBean.setSecurityManager(securityManager);
|
||||||
|
|
||||||
|
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
|
||||||
|
//注意过滤器配置顺序 不能颠倒
|
||||||
|
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl
|
||||||
|
filterChainDefinitionMap.put("/logout", "logout");
|
||||||
|
// 配置不会被拦截的链接 顺序判断
|
||||||
|
filterChainDefinitionMap.put("/druid/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/css/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/fonts/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/js/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/uploadFile/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/login", "anon");
|
||||||
|
|
||||||
|
filterChainDefinitionMap.put("/api/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/ws/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/wss/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/wx/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/**", "auth");
|
||||||
|
//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
|
||||||
|
shiroFilterFactoryBean.setLoginUrl("/login");
|
||||||
|
// 登录成功后要跳转的链接
|
||||||
|
shiroFilterFactoryBean.setSuccessUrl("/index");
|
||||||
|
//未授权界面;
|
||||||
|
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
|
||||||
|
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
||||||
|
|
||||||
|
Map<String, Filter> filtersMap = new LinkedHashMap<>();
|
||||||
|
filtersMap.put("auth", baseFormAuthenticationFilter());
|
||||||
|
shiroFilterFactoryBean.setFilters(filtersMap);
|
||||||
|
|
||||||
|
filterChainDefinitionMap.put("/**", "auth");
|
||||||
|
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
||||||
|
|
||||||
|
return shiroFilterFactoryBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 凭证匹配器
|
||||||
|
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public HashedCredentialsMatcher hashedCredentialsMatcher() {
|
||||||
|
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
|
||||||
|
// 散列算法:这里使用MD5算法;
|
||||||
|
hashedCredentialsMatcher.setHashAlgorithmName("SHA-1");
|
||||||
|
// 散列的次数,比如散列两次,相当于 md5(md5(""));
|
||||||
|
hashedCredentialsMatcher.setHashIterations(1024);
|
||||||
|
return hashedCredentialsMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BaseShiroRealm baseShiroRealm() {
|
||||||
|
BaseShiroRealm shiroRealm = new BaseShiroRealm();
|
||||||
|
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
|
||||||
|
return shiroRealm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityManager securityManager() {
|
||||||
|
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
||||||
|
securityManager.setRealm(baseShiroRealm());
|
||||||
|
// 自定义session管理 使用redis
|
||||||
|
securityManager.setSessionManager(sessionManager());
|
||||||
|
return securityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义sessionManager
|
||||||
|
* */
|
||||||
|
@Bean
|
||||||
|
public SessionManager sessionManager() {
|
||||||
|
BaseSessionManager sessionManager = new BaseSessionManager();
|
||||||
|
sessionManager.setSessionDAO(new MemorySessionDAO());
|
||||||
|
sessionManager.setSessionIdUrlRewritingEnabled(false);
|
||||||
|
sessionManager.setGlobalSessionTimeout(21600000L);
|
||||||
|
return sessionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启shiro aop注解支持.
|
||||||
|
* 使用代理方式;所以需要开启代码支持;
|
||||||
|
*
|
||||||
|
* @param securityManager
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
||||||
|
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
|
||||||
|
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
|
||||||
|
return authorizationAttributeSourceAdvisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shiro生命周期处理器
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
|
||||||
|
return new LifecycleBeanPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
|
||||||
|
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
|
||||||
|
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
|
||||||
|
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
|
||||||
|
return authorizationAttributeSourceAdvisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FormAuthenticationFilter baseFormAuthenticationFilter(){
|
||||||
|
FormAuthenticationFilter formAuthenticationFilter = new ShiroLoginFilter();
|
||||||
|
return formAuthenticationFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean someFilterRegistration() {
|
||||||
|
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||||
|
FormAuthenticationFilter baseFormAuthenticationFilter = new ShiroLoginFilter();
|
||||||
|
registration.setFilter(baseFormAuthenticationFilter);
|
||||||
|
registration.setEnabled(false);
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
}
|
75
src/main/java/com/rymcu/forest/config/ShiroLoginFilter.java
Normal file
75
src/main/java/com/rymcu/forest/config/ShiroLoginFilter.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||||
|
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
||||||
|
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author wanwh
|
||||||
|
* @date 2019/1/24 0024
|
||||||
|
*/
|
||||||
|
public class ShiroLoginFilter extends FormAuthenticationFilter {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在访问controller前判断是否登录,返回json,不进行重定向。
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
|
||||||
|
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||||
|
if (this.isLoginRequest(request, response)) {
|
||||||
|
if (this.isLoginSubmission(request, response)) {
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace("Login submission detected. Attempting to execute login.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.executeLogin(request, response);
|
||||||
|
} else {
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace("Login page view.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else if(isAjax((HttpServletRequest) request)){
|
||||||
|
httpServletResponse.setContentType("application/json");
|
||||||
|
httpServletResponse.setCharacterEncoding("UTF-8");
|
||||||
|
httpServletResponse.setHeader("sessionstatus", "timeOut");
|
||||||
|
httpServletResponse.addHeader("loginPath", this.getLoginUrl());
|
||||||
|
httpServletResponse.getWriter().write(JSONObject.toJSONString(GlobalResultGenerator.genErrorResult("未登录或已登录超时,请重新登录"), SerializerFeature.PrettyFormat));
|
||||||
|
return false;
|
||||||
|
}else {
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace("Attempting to access a path which requires authentication. Forwarding to the Authentication url [" + this.getLoginUrl() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveRequestAndRedirectToLogin(request, response);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAjax(HttpServletRequest request) {
|
||||||
|
String requestedWith = request.getHeader("x-requested-with");
|
||||||
|
if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户和密码(包含验证码)令牌类
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private String captcha;
|
||||||
|
private boolean mobileLogin;
|
||||||
|
|
||||||
|
public UsernamePasswordToken() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UsernamePasswordToken(String username, char[] password,
|
||||||
|
boolean rememberMe, String host, String captcha, boolean mobileLogin) {
|
||||||
|
super(username, password, rememberMe, host);
|
||||||
|
this.captcha = captcha;
|
||||||
|
this.mobileLogin = mobileLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCaptcha() {
|
||||||
|
return captcha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCaptcha(String captcha) {
|
||||||
|
this.captcha = captcha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMobileLogin() {
|
||||||
|
return mobileLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
87
src/main/java/com/rymcu/forest/config/WebLogAspect.java
Normal file
87
src/main/java/com/rymcu/forest/config/WebLogAspect.java
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import com.rymcu.forest.util.Utils;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebLogAspect 实现Web层的日志切面
|
||||||
|
*
|
||||||
|
* @author suwen
|
||||||
|
* @date 2020/12/22 9:16 上午
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class WebLogAspect {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
ThreadLocal<Long> startTime = new ThreadLocal<Long>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义一个切入点. 解释下:
|
||||||
|
*
|
||||||
|
* <p>~ 第一个 * 代表任意修饰符及任意返回值. ~ 第二个 * 任意包名 ~ 第三个 * 代表任意方法.
|
||||||
|
*
|
||||||
|
* <p>~ 第四个 * 定义在web包或者子包 ~ 第五个 * 任意方法 ~ .. 匹配任意数量的参数. execution(*
|
||||||
|
* xiao.ze.demo.service.impl.*.*(..))
|
||||||
|
*/
|
||||||
|
@Pointcut("execution(* com.rymcu.forest.*.api.*.*.*(..))")
|
||||||
|
public void webLog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before("webLog()")
|
||||||
|
public void doBefore(JoinPoint joinPoint) {
|
||||||
|
|
||||||
|
startTime.set(System.currentTimeMillis());
|
||||||
|
|
||||||
|
// 接收到请求,记录请求内容
|
||||||
|
logger.info("WebLogAspect.doBefore()");
|
||||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
HttpServletRequest request = attributes.getRequest();
|
||||||
|
// 记录下请求内容
|
||||||
|
logger.info("URL : " + request.getRequestURL().toString());
|
||||||
|
logger.info("HTTP_METHOD : " + request.getMethod());
|
||||||
|
logger.info("IP : " + Utils.getIpAddress(request));
|
||||||
|
logger.info(
|
||||||
|
"CLASS_METHOD : "
|
||||||
|
+ joinPoint.getSignature().getDeclaringTypeName()
|
||||||
|
+ "."
|
||||||
|
+ joinPoint.getSignature().getName());
|
||||||
|
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs())
|
||||||
|
.replaceAll("(?<=password).*?(?=(nickname|$))", "=****, ")
|
||||||
|
.replaceAll("(?<=password).*?(?=(\\)|$))", "=****)]")
|
||||||
|
.replaceAll("(?<=password).*?(?=(code|$))", "=****, "));
|
||||||
|
|
||||||
|
// 获取所有参数方法一:
|
||||||
|
Enumeration<String> enu = request.getParameterNames();
|
||||||
|
while (enu.hasMoreElements()) {
|
||||||
|
String paraName = enu.nextElement();
|
||||||
|
if ("password".equals(paraName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logger.info(paraName + ": " + request.getParameter(paraName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterReturning("webLog()")
|
||||||
|
public void doAfterReturning(JoinPoint joinPoint) {
|
||||||
|
|
||||||
|
// 处理完请求,返回内容
|
||||||
|
logger.info("WebLogAspect.doAfterReturning()");
|
||||||
|
logger.info("耗时(毫秒) : " + (System.currentTimeMillis() - startTime.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
98
src/main/java/com/rymcu/forest/config/WebMvcConfigurer.java
Normal file
98
src/main/java/com/rymcu/forest/config/WebMvcConfigurer.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||||
|
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||||
|
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||||
|
import com.rymcu.forest.jwt.aop.RestAuthTokenInterceptor;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring MVC 配置
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class WebMvcConfigurer extends WebMvcConfigurationSupport {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||||
|
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||||
|
FastJsonConfig config = new FastJsonConfig();
|
||||||
|
// 保留空的字段
|
||||||
|
config.setSerializerFeatures(SerializerFeature.WriteMapNullValue,
|
||||||
|
//String null -> ""
|
||||||
|
SerializerFeature.WriteNullStringAsEmpty);
|
||||||
|
// SerializerFeature.WriteNullNumberAsZero);//Number null -> 0
|
||||||
|
//关闭循环引用
|
||||||
|
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
|
||||||
|
converter.setFastJsonConfig(config);
|
||||||
|
converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON));
|
||||||
|
converter.setDefaultCharset(Charset.forName("UTF-8"));
|
||||||
|
converters.add(0, converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解决跨域问题
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**")
|
||||||
|
.allowedOriginPatterns(CorsConfiguration.ALL)
|
||||||
|
.allowCredentials(true)
|
||||||
|
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestAuthTokenInterceptor restAuthTokenInterceptor() {
|
||||||
|
return new RestAuthTokenInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加拦截器
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(restAuthTokenInterceptor()).addPathPatterns("/api/**")
|
||||||
|
.excludePathPatterns("/api/v1/console/**", "/api/v1/article/articles/**", "/api/v1/article/detail/**"
|
||||||
|
, "/api/v1/topic/**", "/api/v1/user/**", "/api/v1/article/*/comments", "/api/v1/rule/currency/**", "/api/v1/lucene/**", "/api/v1/open-data/**");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问静态资源
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
/**
|
||||||
|
* SpringBoot自动配置本身并不会把/swagger-ui.html
|
||||||
|
* 这个路径映射到对应的目录META-INF/resources/下面
|
||||||
|
* 采用WebMvcConfigurerAdapter将swagger的静态文件进行发布;
|
||||||
|
*/
|
||||||
|
registry.addResourceHandler("swagger-ui.html")
|
||||||
|
.addResourceLocations("classpath:/META-INF/resources/");
|
||||||
|
|
||||||
|
registry.addResourceHandler("/webjars/**")
|
||||||
|
.addResourceLocations("classpath:/META-INF/resources/webjars/");
|
||||||
|
//将所有/static/** 访问都映射到classpath:/static/ 目录下
|
||||||
|
registry.addResourceHandler("/static/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/");
|
||||||
|
super.addResourceHandlers(registry);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||||
|
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||||
|
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSocketMessageBroker
|
||||||
|
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
|
||||||
|
/**
|
||||||
|
* 注册stomp端点
|
||||||
|
* @param registry
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||||
|
// 允许使用socketJs方式访问 即可通过http://IP:PORT/ws来和服务端websocket连接
|
||||||
|
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
|
||||||
|
registry.addEndpoint("/wss").setAllowedOrigins("*").withSockJS();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置信息代理
|
||||||
|
* @param registry
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||||
|
|
||||||
|
// 订阅Broker名称 user点对点 topic广播即群发
|
||||||
|
registry.enableSimpleBroker("/topic", "/user");
|
||||||
|
// 全局(客户端)使用的消息前缀
|
||||||
|
registry.setApplicationDestinationPrefixes("/app");
|
||||||
|
// 点对点使用的前缀 无需配置 默认/user
|
||||||
|
registry.setUserDestinationPrefix("/user");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.rymcu.forest.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息通知类型
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class NotificationConstant {
|
||||||
|
|
||||||
|
public static String Article = "0";
|
||||||
|
|
||||||
|
public static String Follow = "1";
|
||||||
|
|
||||||
|
public static String Comment = "2";
|
||||||
|
|
||||||
|
public static String PostArticle = "3";
|
||||||
|
|
||||||
|
public static String UpdateArticle = "4";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.rymcu.forest.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目常量
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public final class ProjectConstant {
|
||||||
|
/**当前环境*/
|
||||||
|
public static final String ENV = "dev";
|
||||||
|
/**项目基础包名称,根据自己公司的项目修改*/
|
||||||
|
public static final String BASE_PACKAGE = "com.rymcu.forest";
|
||||||
|
/**DTO所在包*/
|
||||||
|
public static final String DTO_PACKAGE = BASE_PACKAGE + ".dto";
|
||||||
|
/**Model所在包*/
|
||||||
|
public static final String MODEL_PACKAGE = BASE_PACKAGE + ".entity";
|
||||||
|
/**Mapper所在包*/
|
||||||
|
public static final String MAPPER_PACKAGE = BASE_PACKAGE + ".mapper";
|
||||||
|
/**Service所在包*/
|
||||||
|
public static final String SERVICE_PACKAGE = BASE_PACKAGE + ".service";
|
||||||
|
/**ServiceImpl所在包*/
|
||||||
|
public static final String SERVICE_IMPL_PACKAGE = SERVICE_PACKAGE + ".impl";
|
||||||
|
/**Controller所在包*/
|
||||||
|
public static final String CONTROLLER_PACKAGE = BASE_PACKAGE + ".web";
|
||||||
|
/**Mapper插件基础接口的完全限定名*/
|
||||||
|
public static final String MAPPER_INTERFACE_REFERENCE = BASE_PACKAGE + ".core.mapper.Mapper";
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.rymcu.forest.core.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shiro通用常量
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public interface ShiroConstants {
|
||||||
|
/**
|
||||||
|
* 当前登录的用户
|
||||||
|
*/
|
||||||
|
public static final String CURRENT_USER = "currentUser";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
|
public static final String CURRENT_USERNAME = "username";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息key
|
||||||
|
*/
|
||||||
|
public static String MESSAGE = "message";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误key
|
||||||
|
*/
|
||||||
|
public static String ERROR = "errorMsg";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码格式
|
||||||
|
*/
|
||||||
|
public static String ENCODING = "UTF-8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前在线会话
|
||||||
|
*/
|
||||||
|
public String ONLINE_SESSION = "online_session";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码key
|
||||||
|
*/
|
||||||
|
public static final String CURRENT_CAPTCHA = "captcha";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码开关
|
||||||
|
*/
|
||||||
|
public static final String CURRENT_ENABLED = "captchaEnabled";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码开关
|
||||||
|
*/
|
||||||
|
public static final String CURRENT_TYPE = "captchaType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码
|
||||||
|
*/
|
||||||
|
public static final String CURRENT_VALIDATE_CODE = "validateCode";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码错误
|
||||||
|
*/
|
||||||
|
public static final String CAPTCHA_ERROR = "captchaError";
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.AccountException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2022/8/25 19:27.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
*/
|
||||||
|
public class AccountExistsException extends AccountException {
|
||||||
|
private static final long serialVersionUID = 3206734387536223284L;
|
||||||
|
|
||||||
|
public AccountExistsException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountExistsException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountExistsException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountExistsException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author KKould
|
||||||
|
*/
|
||||||
|
public class BusinessException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3206744387536223284L;
|
||||||
|
|
||||||
|
public BusinessException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码错误异常类
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class CaptchaException extends AuthenticationException
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public CaptchaException()
|
||||||
|
{
|
||||||
|
super("验证码不正确");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author KKould
|
||||||
|
*/
|
||||||
|
public class ContentNotExistException extends BusinessException {
|
||||||
|
private static final long serialVersionUID = 3206734387536223284L;
|
||||||
|
|
||||||
|
public ContentNotExistException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentNotExistException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentNotExistException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentNotExistException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentNotExistException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2022/8/25 19:11.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
*/
|
||||||
|
public class NicknameOccupyException extends BusinessException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3206744387536223284L;
|
||||||
|
|
||||||
|
public NicknameOccupyException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NicknameOccupyException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NicknameOccupyException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NicknameOccupyException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NicknameOccupyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.result.ResultCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务(业务)异常如“ 账号或密码错误 ”,该异常只做INFO级别的日志记录 @see WebMvcConfigurer
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class ServiceException extends Exception {
|
||||||
|
private int code;
|
||||||
|
private String extraMessage;
|
||||||
|
|
||||||
|
public ServiceException(ResultCode resultCode) {
|
||||||
|
super(resultCode.getMessage());
|
||||||
|
this.code=resultCode.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ServiceException(String message, Throwable cause) {
|
||||||
|
|
||||||
|
}
|
||||||
|
public ServiceException(int code, String message, String extraMessage, Throwable cause){
|
||||||
|
super(message,cause);
|
||||||
|
this.code=code;
|
||||||
|
this.extraMessage=extraMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public ServiceException(ResultCode resultCode, String extraMessage){
|
||||||
|
this(resultCode.getCode(),resultCode.getMessage(),extraMessage,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(String extraMessage){
|
||||||
|
this(ResultCode.INVALID_PARAM,extraMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtraMessage() {
|
||||||
|
return extraMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
import com.rymcu.forest.enumerate.TransactionCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class TransactionException extends BusinessException {
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public TransactionException(TransactionCode transactionCode) {
|
||||||
|
super(transactionCode.getMessage());
|
||||||
|
this.code = transactionCode.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author KKould
|
||||||
|
*/
|
||||||
|
public class UltraViresException extends BusinessException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3206744387536228284L;
|
||||||
|
|
||||||
|
public UltraViresException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UltraViresException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UltraViresException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UltraViresException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UltraViresException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/core/mapper/Mapper.java
Normal file
17
src/main/java/com/rymcu/forest/core/mapper/Mapper.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.core.mapper;
|
||||||
|
|
||||||
|
import tk.mybatis.mapper.common.BaseMapper;
|
||||||
|
import tk.mybatis.mapper.common.ConditionMapper;
|
||||||
|
import tk.mybatis.mapper.common.IdsMapper;
|
||||||
|
import tk.mybatis.mapper.common.special.InsertListMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定制版MyBatis Mapper插件接口,如需其他接口参考官方文档自行添加。
|
||||||
|
*/
|
||||||
|
public interface Mapper<T>
|
||||||
|
extends
|
||||||
|
BaseMapper<T>,
|
||||||
|
ConditionMapper<T>,
|
||||||
|
IdsMapper<T>,
|
||||||
|
InsertListMapper<T> {
|
||||||
|
}
|
21
src/main/java/com/rymcu/forest/core/mapper/TreeMapper.java
Normal file
21
src/main/java/com/rymcu/forest/core/mapper/TreeMapper.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package com.rymcu.forest.core.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface TreeMapper<T> extends Mapper<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 找到所有子节点
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<T> findByParentIdsLike(T entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新所有父节点字段
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int updateParentIds(T entity);
|
||||||
|
|
||||||
|
}
|
19
src/main/java/com/rymcu/forest/core/result/GlobalResult.java
Normal file
19
src/main/java/com/rymcu/forest/core/result/GlobalResult.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.rymcu.forest.core.result;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GlobalResult<T> {
|
||||||
|
private boolean success = false;
|
||||||
|
private T data;
|
||||||
|
private int code;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public GlobalResult() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> GlobalResult<T> newInstance() {
|
||||||
|
return new GlobalResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package com.rymcu.forest.core.result;
|
||||||
|
|
||||||
|
import com.rymcu.forest.util.ErrorCode;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class GlobalResultGenerator {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalResultGenerator.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normal
|
||||||
|
* @param success
|
||||||
|
* @param data
|
||||||
|
* @param message
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> GlobalResult<T> genResult(boolean success, T data, String message) {
|
||||||
|
GlobalResult<T> result = GlobalResult.newInstance();
|
||||||
|
result.setSuccess(success);
|
||||||
|
result.setData(data);
|
||||||
|
result.setMessage(message);
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("generate rest result:{}", result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* success
|
||||||
|
* @param data
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> GlobalResult<T> genSuccessResult(T data) {
|
||||||
|
|
||||||
|
return genResult(true, data, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error message
|
||||||
|
* @param message error message
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> GlobalResult<T> genErrorResult(String message) {
|
||||||
|
|
||||||
|
return genResult(false, null, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error
|
||||||
|
* @param error error enum
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> GlobalResult<T> genErrorResult(ErrorCode error) {
|
||||||
|
|
||||||
|
return genErrorResult(error.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* success no message
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static GlobalResult genSuccessResult() {
|
||||||
|
return genSuccessResult(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* success
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> GlobalResult<T> genSuccessResult(String message) {
|
||||||
|
|
||||||
|
return genResult(true, null, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.rymcu.forest.core.result;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum GlobalResultMessage {
|
||||||
|
|
||||||
|
SUCCESS("操作成功!"),
|
||||||
|
FAIL("操作失败!"),
|
||||||
|
SEND_FAIL("发送失败,请稍后再试!"),
|
||||||
|
SEND_SUCCESS("验证码已发送至邮箱!");
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
GlobalResultMessage(String message){
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
37
src/main/java/com/rymcu/forest/core/result/ResultCode.java
Normal file
37
src/main/java/com/rymcu/forest/core/result/ResultCode.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package com.rymcu.forest.core.result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应码枚举,参考HTTP状态码的语义
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public enum ResultCode {
|
||||||
|
// 成功
|
||||||
|
SUCCESS(1, "SUCCESS"),
|
||||||
|
// 失败
|
||||||
|
FAIL(400, "访问失败"),
|
||||||
|
// 未认证(签名错误)
|
||||||
|
UNAUTHORIZED(401, "签名错误"),
|
||||||
|
// 接口不存在
|
||||||
|
NOT_FOUND(404, "此接口不存在"),
|
||||||
|
// 服务器内部错误
|
||||||
|
INTERNAL_SERVER_ERROR(500, "系统繁忙,请稍后再试"),
|
||||||
|
// 参数错误
|
||||||
|
INVALID_PARAM(10000, "参数错误");
|
||||||
|
private int code;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
ResultCode(int code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.rymcu.forest.core.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.exception.ServiceException;
|
||||||
|
import com.rymcu.forest.core.mapper.Mapper;
|
||||||
|
import org.apache.ibatis.exceptions.TooManyResultsException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import tk.mybatis.mapper.entity.Condition;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于通用MyBatis Mapper插件的Service接口的实现
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public abstract class AbstractService<T> implements Service<T> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected Mapper<T> mapper;
|
||||||
|
/**
|
||||||
|
* 当前泛型真实类型的Class
|
||||||
|
*/
|
||||||
|
private Class<T> modelClass;
|
||||||
|
|
||||||
|
public AbstractService() {
|
||||||
|
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
|
||||||
|
modelClass = (Class<T>) pt.getActualTypeArguments()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(T model) {
|
||||||
|
mapper.insertSelective(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(List<T> models) {
|
||||||
|
mapper.insertList(models);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteById(String id) {
|
||||||
|
mapper.deleteByPrimaryKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteByIds(String ids) {
|
||||||
|
mapper.deleteByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(T model) {
|
||||||
|
mapper.updateByPrimaryKeySelective(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T findById(String id) {
|
||||||
|
return mapper.selectByPrimaryKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T findBy(String fieldName, Object value) throws TooManyResultsException, ServiceException {
|
||||||
|
try {
|
||||||
|
T model = modelClass.newInstance();
|
||||||
|
Field field = modelClass.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(model, value);
|
||||||
|
return mapper.selectOne(model);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new ServiceException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> findByIds(String ids) {
|
||||||
|
return mapper.selectByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> findByCondition(Condition condition) {
|
||||||
|
return mapper.selectByCondition(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> findAll() {
|
||||||
|
return mapper.selectAll();
|
||||||
|
}
|
||||||
|
}
|
92
src/main/java/com/rymcu/forest/core/service/Service.java
Normal file
92
src/main/java/com/rymcu/forest/core/service/Service.java
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package com.rymcu.forest.core.service;
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.exception.ServiceException;
|
||||||
|
import org.apache.ibatis.exceptions.TooManyResultsException;
|
||||||
|
import tk.mybatis.mapper.entity.Condition;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service 层 基础接口,其他Service 接口 请继承该接口
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public interface Service<T> {
|
||||||
|
/**
|
||||||
|
* 持久化
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
*/
|
||||||
|
void save(T model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量持久化
|
||||||
|
*
|
||||||
|
* @param models
|
||||||
|
*/
|
||||||
|
void save(List<T> models);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过主鍵刪除
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void deleteById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量刪除 eg:ids -> “1,2,3,4”
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
void deleteByIds(String ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
*/
|
||||||
|
void update(T model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过ID查找
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T findById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束
|
||||||
|
*
|
||||||
|
* @param fieldName
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
* @throws TooManyResultsException
|
||||||
|
* @throws ServiceException
|
||||||
|
*/
|
||||||
|
T findBy(String fieldName, Object value) throws TooManyResultsException, ServiceException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过多个ID查找//eg:ids -> “1,2,3,4”
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<T> findByIds(String ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查找
|
||||||
|
*
|
||||||
|
* @param condition
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<T> findByCondition(Condition condition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<T> findAll();
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.rymcu.forest.core.service.log;
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
|
import com.rymcu.forest.core.service.log.annotation.TransactionLogger;
|
||||||
|
import com.rymcu.forest.entity.TransactionRecord;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
|
import com.rymcu.forest.service.TransactionRecordService;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class TransactionAspect {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(TransactionAspect.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TransactionRecordService transactionRecordService;
|
||||||
|
|
||||||
|
@Pointcut("@annotation(com.rymcu.forest.core.service.log.annotation.TransactionLogger)")
|
||||||
|
public void pointCut() {}
|
||||||
|
/**
|
||||||
|
* 保存交易操作日志
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @return 方法执行结果
|
||||||
|
* @throws Throwable 调用出错
|
||||||
|
*/
|
||||||
|
@AfterReturning(value = "pointCut()", returning="obj")
|
||||||
|
public void save(JoinPoint joinPoint, Object obj) throws Exception {
|
||||||
|
logger.info("保存交易记录 start ...");
|
||||||
|
/**
|
||||||
|
* 解析Log注解
|
||||||
|
*/
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
Method method = currentMethod(joinPoint, methodName);
|
||||||
|
TransactionLogger log = method.getAnnotation(TransactionLogger.class);
|
||||||
|
if (Objects.nonNull(log)) {
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
GlobalResult globalResult = (GlobalResult) obj;
|
||||||
|
if (globalResult.isSuccess()) {
|
||||||
|
if (TransactionEnum.Answer.equals(log.transactionType())) {
|
||||||
|
if (globalResult.getData().equals(true)) {
|
||||||
|
transactionRecordService.bankTransfer(user.getIdUser(), TransactionEnum.CorrectAnswer);
|
||||||
|
} else {
|
||||||
|
transactionRecordService.bankTransfer(user.getIdUser(), TransactionEnum.Answer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("保存交易记录 end ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前执行的方法
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @param methodName 方法名称
|
||||||
|
* @return 方法
|
||||||
|
*/
|
||||||
|
private Method currentMethod(JoinPoint joinPoint, String methodName) {
|
||||||
|
/**
|
||||||
|
* 获取目标类的所有方法,找到当前要执行的方法
|
||||||
|
*/
|
||||||
|
Method[] methods = joinPoint.getTarget().getClass().getMethods();
|
||||||
|
Method resultMethod = null;
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.getName().equals(methodName)) {
|
||||||
|
resultMethod = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultMethod;
|
||||||
|
}
|
||||||
|
}
|
114
src/main/java/com/rymcu/forest/core/service/log/VisitAspect.java
Normal file
114
src/main/java/com/rymcu/forest/core/service/log/VisitAspect.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package com.rymcu.forest.core.service.log;
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.service.log.constant.LoggerConstant;
|
||||||
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
|
import com.rymcu.forest.entity.Visit;
|
||||||
|
import com.rymcu.forest.jwt.def.JwtConstants;
|
||||||
|
import com.rymcu.forest.service.ArticleService;
|
||||||
|
import com.rymcu.forest.service.VisitService;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import com.rymcu.forest.util.Utils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 浏览
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class VisitAspect {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(VisitAspect.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ArticleService articleService;
|
||||||
|
@Resource
|
||||||
|
private VisitService visitService;
|
||||||
|
|
||||||
|
@Pointcut("@annotation(com.rymcu.forest.core.service.log.annotation.VisitLogger)")
|
||||||
|
public void pointCut() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存系统操作日志
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @return 方法执行结果
|
||||||
|
* @throws Throwable 调用出错
|
||||||
|
*/
|
||||||
|
@AfterReturning(value = "pointCut()", returning = "obj")
|
||||||
|
public void save(JoinPoint joinPoint, Object obj) {
|
||||||
|
logger.info("保存访问记录 start ...");
|
||||||
|
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
|
String ip = Utils.getIpAddress(request);
|
||||||
|
String url = request.getRequestURL().toString();
|
||||||
|
String ua = request.getHeader("user-agent");
|
||||||
|
String referer = request.getHeader("Referer");
|
||||||
|
String fingerprint = request.getHeader("fingerprint");
|
||||||
|
Visit visit = new Visit();
|
||||||
|
visit.setVisitUrl(url);
|
||||||
|
visit.setVisitIp(ip);
|
||||||
|
visit.setVisitUa(ua);
|
||||||
|
visit.setVisitCity("");
|
||||||
|
visit.setVisitDeviceId(fingerprint);
|
||||||
|
visit.setVisitRefererUrl(referer);
|
||||||
|
visit.setCreatedTime(new Date());
|
||||||
|
String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
|
||||||
|
if (StringUtils.isNotBlank(authHeader)) {
|
||||||
|
TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
|
||||||
|
if (Objects.nonNull(tokenUser)) {
|
||||||
|
visit.setVisitUserId(tokenUser.getIdUser());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visitService.save(visit);
|
||||||
|
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
Map params = getParams(request);
|
||||||
|
if (params.isEmpty()) {
|
||||||
|
params = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||||
|
} else {
|
||||||
|
params.putAll((Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE));
|
||||||
|
}
|
||||||
|
switch (methodName) {
|
||||||
|
case LoggerConstant.ARTICLE:
|
||||||
|
String param = String.valueOf(params.get("id"));
|
||||||
|
if (StringUtils.isBlank(param) || "undefined".equals(param) || "null".equals(param)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Long id = Long.parseLong(param);
|
||||||
|
articleService.incrementArticleViewCount(id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
logger.info("保存访问记录 end ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getParams(HttpServletRequest request) {
|
||||||
|
Map<String, String> paramsMap = new HashMap<>(10);
|
||||||
|
Enumeration<String> paraNames = request.getParameterNames();
|
||||||
|
while (paraNames.hasMoreElements()) {
|
||||||
|
String key = paraNames.nextElement();
|
||||||
|
if ("password".equals(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
paramsMap.put(key, request.getParameter(key));
|
||||||
|
}
|
||||||
|
return paramsMap;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.rymcu.forest.core.service.log.annotation;
|
||||||
|
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TransactionLogger {
|
||||||
|
|
||||||
|
TransactionEnum transactionType();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.rymcu.forest.core.service.log.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 浏览记录器
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface VisitLogger {
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.rymcu.forest.core.service.log.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class LoggerConstant {
|
||||||
|
|
||||||
|
public final static String ARTICLE = "article";
|
||||||
|
|
||||||
|
public final static String ARTICLES = "articles";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package com.rymcu.forest.core.service.redis;
|
||||||
|
|
||||||
|
import com.rymcu.forest.entity.BaseDO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis 中取得的结果
|
||||||
|
* Created by liwei on 2017/2/7.
|
||||||
|
*/
|
||||||
|
public class RedisResult<T> extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis中是否存在
|
||||||
|
*/
|
||||||
|
private boolean exist = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis中取得的数据
|
||||||
|
*/
|
||||||
|
private T result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis中取得的List数据
|
||||||
|
*/
|
||||||
|
private List<T> listResult;
|
||||||
|
/**
|
||||||
|
* redis中的key是否存在。true:表示redis中存在Key,但对应的值为空值标记
|
||||||
|
*/
|
||||||
|
private boolean keyExists = false;
|
||||||
|
/**
|
||||||
|
* redis中key 对应在对象值
|
||||||
|
*/
|
||||||
|
private T resultObj;
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isExist() {
|
||||||
|
return exist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExist(boolean exist) {
|
||||||
|
this.exist = exist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResult(T result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> getListResult() {
|
||||||
|
return listResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListResult(List<T> listResult) {
|
||||||
|
this.listResult = listResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyExists(boolean keyExists) {
|
||||||
|
this.keyExists = keyExists;
|
||||||
|
}
|
||||||
|
public boolean isKeyExists() {
|
||||||
|
return keyExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResultObj() {
|
||||||
|
return resultObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResultObj(T resultObj) {
|
||||||
|
this.resultObj = resultObj;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,264 @@
|
|||||||
|
package com.rymcu.forest.core.service.redis;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis 服务接口
|
||||||
|
* @author Jimersy Lee
|
||||||
|
* 2017-09-18 14:58:21
|
||||||
|
*/
|
||||||
|
public interface RedisService {
|
||||||
|
/**
|
||||||
|
* NX: 当且仅当缓存中特定的key不存在时设定数据
|
||||||
|
*/
|
||||||
|
String NXXX_SET_IF_NOT_EXISTS = "nx";
|
||||||
|
/**
|
||||||
|
* XX: 当且仅当缓存中特定的key存在时设定数据
|
||||||
|
*/
|
||||||
|
String NXXX_SET_IF_EXISTS = "xx";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EX:缓存失效的时间单位:秒
|
||||||
|
*/
|
||||||
|
String EXPX_SECONDS = "ex";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EX:缓存失效的时间单位:毫秒
|
||||||
|
*/
|
||||||
|
String EXPX_MILLISECOND = "px";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认过期时间 ,3600(秒)
|
||||||
|
*/
|
||||||
|
int DEFAULT_EXPIRE_TIME = 3600;
|
||||||
|
|
||||||
|
ObjectMapper om = new ObjectMapper();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空白占位符
|
||||||
|
*/
|
||||||
|
String BLANK_CONTENT = "__BLANK__";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化操作
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 从连接池里取连接(用完连接后必须销毁)
|
||||||
|
// *
|
||||||
|
// * @return
|
||||||
|
// */
|
||||||
|
// Jedis getResource();
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 用完后,销毁连接(必须)
|
||||||
|
// *
|
||||||
|
// * @param jedis
|
||||||
|
// */
|
||||||
|
// void destroyResource(Jedis jedis);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取数据
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String get(String key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取对象数据(不支持Collection数据类型)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param clazz
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
<T> T get(String key, Class<T> clazz);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取对象数据(不支持Collection数据类型)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param clazz
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
<T> RedisResult<T> getResult(String key, Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取 Collection 对象数据
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param elementClazz 集合元素类型
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
<T> RedisResult<T> getListResult(String key, Class<T> elementClazz);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param obj
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String set(String key, Object obj);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String set(String key, String value);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容(无论key是否存在,均会更新key对应的值)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param obj
|
||||||
|
* @param expireTime 缓存内容过期时间 (单位:秒) ,若expireTime小于0 则表示该内容不过期
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String set(String key, Object obj, int expireTime);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容(无论key是否存在,均会更新key对应的值)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param expireTime 缓存内容过期时间 (单位:秒) ,若expireTime小于0 则表示该内容不过期
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String set(String key, String value, int expireTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param nxxx 缓存写入值模式 详见 {@link RedisService#NXXX_SET_IF_EXISTS}, {@link RedisService#NXXX_SET_IF_NOT_EXISTS}
|
||||||
|
* @param expx 缓存超时时间单位 详见{@link RedisService#EXPX_SECONDS}, {@link RedisService#EXPX_MILLISECOND}
|
||||||
|
* @param expiredTime 缓存存活时长,必须 大于0
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String set(String key, String value, String nxxx, String expx, long expiredTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅当redis中不含对应的key时,设定缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param expiredTime 缓存内容过期时间 (单位:秒) ,若expireTime小于0 则表示该内容不过期
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String setnx(String key, String value, long expiredTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅当redis中含有对应的key时,修改缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param expiredTime 缓存内容过期时间 (单位:秒) ,若expireTime小于0 则表示该内容不过期
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String setxx(String key, String value, long expiredTime);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key删除缓存,
|
||||||
|
*
|
||||||
|
* @param keys
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Long delete(String... keys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断对应的key是否存在
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean exists(String key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis 加法运算
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return 运算结果
|
||||||
|
*/
|
||||||
|
Long incrBy(String key, long value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设定redis 对应的key的剩余存活时间
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param seconds
|
||||||
|
*/
|
||||||
|
void setTTL(String key, int seconds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据通配符表达式查询key值的set,通配符仅支持*
|
||||||
|
*
|
||||||
|
* @param pattern 如 ke6*abc等
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Set<String> keys(String pattern);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转为json字符串。若对象为null,则返回 {@link RedisService#BLANK_CONTENT}
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String toJsonString(Object object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* json序列化对象。
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @return 返回序列化后的字符串。若value为null,则返回 {@link RedisService#BLANK_CONTENT}
|
||||||
|
*/
|
||||||
|
String makeSerializedString(Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容(无论key是否存在,均会更新key对应的值)
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String put(String cacheName, String key, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容(无论key是否存在,均会更新key对应的值)
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param expireTime 缓存 内容过期时间 (单位:秒) ,若expireTime小于0 则表示该内容不过期
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String put(String cacheName, String key, Object value, int expireTime);
|
||||||
|
|
||||||
|
Object get(String cacheName, String key);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,213 @@
|
|||||||
|
package com.rymcu.forest.core.service.redis.impl;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis Key 辅助类
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Lazy(false)
|
||||||
|
public class RedisKeyHelper {
|
||||||
|
/**
|
||||||
|
* 应用级别前缀
|
||||||
|
*/
|
||||||
|
private static String SYS_PREFIX = "PROJECT_";
|
||||||
|
/**
|
||||||
|
* 用户信息前缀
|
||||||
|
*/
|
||||||
|
private static String UIC_PREFIX = SYS_PREFIX + "UIC_";
|
||||||
|
/**
|
||||||
|
* 商品中心信息前缀
|
||||||
|
*/
|
||||||
|
private static String IC_PREFIX = SYS_PREFIX + "IC_";
|
||||||
|
/**
|
||||||
|
* 交易中心信息前缀
|
||||||
|
*/
|
||||||
|
private static String TC_PREFIX = SYS_PREFIX + "TC_";
|
||||||
|
/**
|
||||||
|
* 优惠中心信息前缀
|
||||||
|
*/
|
||||||
|
private static String PROM_PREFIX = SYS_PREFIX + "PROM_";
|
||||||
|
/**
|
||||||
|
* 会员中心信息前缀
|
||||||
|
*/
|
||||||
|
private static String MMB_PREFIX = SYS_PREFIX + "MMB_";
|
||||||
|
/**
|
||||||
|
* 分布式互斥锁前缀
|
||||||
|
*/
|
||||||
|
private static String LOCK_PREFIX = SYS_PREFIX + "LOCK_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单次登录的默认有效时长(单位:秒)
|
||||||
|
*/
|
||||||
|
public static final int DEFAULT_LOGIN_TIMEOUT = 3600 * 24 * 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签到记录的默认有效时长(单位:秒)
|
||||||
|
*/
|
||||||
|
public static final int MMB_SIGN_TIMEOUT = 3600 * 12;
|
||||||
|
/**
|
||||||
|
* redis中加息券信息的保存时间(单位:秒)
|
||||||
|
*/
|
||||||
|
public static final int PROM_IRC_TIMEOUT = 60 * 3;
|
||||||
|
/**
|
||||||
|
* redis中借款人信息默认有效效时间(单位:秒)
|
||||||
|
*/
|
||||||
|
public static final int BORROWER_EXPIRE_TIMEOUT = 60 * 3;//redis缓存失效时间
|
||||||
|
|
||||||
|
|
||||||
|
//商品中心KEY配置==begin========================================================================================
|
||||||
|
/**
|
||||||
|
* 商品(资产标)前缀
|
||||||
|
*/
|
||||||
|
public static final String IC_ITEM_PREFIX = IC_PREFIX + "ITEM_";
|
||||||
|
/**
|
||||||
|
* 商品(资产标)列表前缀
|
||||||
|
*/
|
||||||
|
public static final String IC_ITEM_LIST_PREFIX = IC_ITEM_PREFIX + "LIST_";
|
||||||
|
/**
|
||||||
|
* 商品已投金额或份数前缀
|
||||||
|
*/
|
||||||
|
public static final String IC_ITEM_INVESTED_AMOUNT_PREFIX = IC_PREFIX + "INTESTED_AMT_";
|
||||||
|
public static final String IC_ITEM_DEAL_CREDITOR_PREFIX = IC_PREFIX + "DEAL_CREDITOR_";
|
||||||
|
|
||||||
|
//商品中心KEY配置==end==========================================================================================
|
||||||
|
//优惠中心KEY配置==begin========================================================================================
|
||||||
|
/**
|
||||||
|
* 加息券信息前缀
|
||||||
|
*/
|
||||||
|
public static String PROM_IRC_PREFIX = PROM_PREFIX + "IRC_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优惠配置信息前缀
|
||||||
|
*/
|
||||||
|
public static String PROM_CONFIG_PREFIX = PROM_PREFIX + "CONFIG_";
|
||||||
|
/**
|
||||||
|
* 红包列表信息前缀
|
||||||
|
*/
|
||||||
|
public static final String PROM_COUPON_LIST_PREFIX = PROM_PREFIX + "COUPON_LIST_";
|
||||||
|
//优惠中心KEY配置==end==========================================================================================
|
||||||
|
//交易中心KEY配置==========================================================================================
|
||||||
|
public static final String TC_TRANS_ACCOUNT_PREFIX = TC_PREFIX + "ACC_";
|
||||||
|
|
||||||
|
public static final String TC_TRANS_CURRENT_DEAL_CONFIG_PREFIX = TC_PREFIX + "CURRENT_DEAL_CONFIG_";
|
||||||
|
|
||||||
|
public static final String TC_TRANS_EXPERIENCE_MONEY_CONFIG_PREFIX = TC_PREFIX + "EXPERIENCE_MONEY_CONFIG_";
|
||||||
|
|
||||||
|
public static final String TC_TRANS_CURRENT_DEAL_LOAD_PREFIX = TC_PREFIX + "CURRENT_DEAL_LOAD_";
|
||||||
|
|
||||||
|
public static final String TC_TRANS_CONST_DEAL_ORDER_LIST_PREFIX = TC_PREFIX + "CURRENT_CONST_DEAL_ORDER_LIST_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水号redis key前缀
|
||||||
|
*/
|
||||||
|
public static final String TC_TRANS_SEQ_PREFIX = TC_PREFIX + "SEQ_";
|
||||||
|
|
||||||
|
//交易中心KEY配置==end==========================================================================================
|
||||||
|
//用户中心KEY配置==========================================================================================
|
||||||
|
/**
|
||||||
|
* redis中登录用户token的key前缀
|
||||||
|
*/
|
||||||
|
public static String LOGIN_TOKEN_KEY_PREFIX = UIC_PREFIX + "LOGIN_TOKEN_";
|
||||||
|
/**
|
||||||
|
* redis中登录用户USERID的key前缀
|
||||||
|
*/
|
||||||
|
public static String LOGIN_UID_KEY_PREFIX = UIC_PREFIX + "LOGIN_UID_";
|
||||||
|
/**
|
||||||
|
* 用户信息前缀(手机号)
|
||||||
|
*/
|
||||||
|
public static String UIC_MOBILE_PREFIX = UIC_PREFIX + "MOB_";
|
||||||
|
/**
|
||||||
|
* 用户角色前缀
|
||||||
|
*/
|
||||||
|
public static String UIC_ROLE_PREFIX = UIC_PREFIX + "B_R_";
|
||||||
|
public static String UIC_ROLE_CANCEL_SUFFIX = UIC_PREFIX + "CNL_";
|
||||||
|
//用户中心KEY配置==end==========================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建分布式锁的key
|
||||||
|
*
|
||||||
|
* @param clazz
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String makeLockKey(Class clazz, String key) {
|
||||||
|
return buildKeyString(LOCK_PREFIX, clazz.getSimpleName(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建分布式锁的key
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String makeLockKey(String key) {
|
||||||
|
return buildKeyString(LOCK_PREFIX, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造商品信息 redis key
|
||||||
|
*
|
||||||
|
* @param itemId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String makeIcItemKey(long itemId) {
|
||||||
|
return buildKeyString(IC_ITEM_PREFIX, itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造商品信息列表 redis key
|
||||||
|
*
|
||||||
|
* @param pageSize
|
||||||
|
* @param pageNo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String makeIcItemListKey(int pageSize, int pageNo) {
|
||||||
|
return buildKeyString(IC_ITEM_LIST_PREFIX, pageSize, pageNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造资产标已投金额前缀
|
||||||
|
*
|
||||||
|
* @param itemId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String makeInvestedAmountKey(long itemId) {
|
||||||
|
return buildKeyString(IC_ITEM_INVESTED_AMOUNT_PREFIX, itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造交易中心流水号前缀
|
||||||
|
*
|
||||||
|
* @param flag
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String makeSeqKey(String flag) {
|
||||||
|
return buildKeyString(TC_TRANS_SEQ_PREFIX, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String buildKeyString(Object... objs) {
|
||||||
|
if (objs == null || objs.length == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
boolean isFirst = true;
|
||||||
|
for (Object obj : objs) {
|
||||||
|
if (isFirst) {
|
||||||
|
isFirst = false;
|
||||||
|
} else {
|
||||||
|
builder.append("_");
|
||||||
|
}
|
||||||
|
if (obj instanceof Class) {
|
||||||
|
builder.append(((Class) obj).getName());
|
||||||
|
} else {
|
||||||
|
builder.append(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,577 @@
|
|||||||
|
package com.rymcu.forest.core.service.redis.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
|
import com.rymcu.forest.config.RedisProperties;
|
||||||
|
import com.rymcu.forest.core.service.redis.RedisResult;
|
||||||
|
import com.rymcu.forest.core.service.redis.RedisService;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import redis.clients.jedis.Jedis;
|
||||||
|
import redis.clients.jedis.JedisPool;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis 服务接口实现类
|
||||||
|
*
|
||||||
|
* @author liwei
|
||||||
|
* 16/10/30 下午5:28
|
||||||
|
*/
|
||||||
|
@Component("redisService")
|
||||||
|
@EnableConfigurationProperties({RedisProperties.class})
|
||||||
|
public class RedisServiceImpl implements RedisService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(RedisServiceImpl.class);
|
||||||
|
|
||||||
|
private static JedisPool pool = null;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisProperties redisProperties;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化操作
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
if (pool != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pool = getJedisPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JedisPool getJedisPool() {
|
||||||
|
if (pool == null) {
|
||||||
|
synchronized (RedisServiceImpl.class) {
|
||||||
|
if (pool == null) {
|
||||||
|
pool = new JedisPool(redisProperties, redisProperties.getHost(),
|
||||||
|
redisProperties.getPort(), redisProperties.getConnectionTimeout(),
|
||||||
|
redisProperties.getSoTimeout(), redisProperties.getPassword(),
|
||||||
|
redisProperties.getDatabase(), redisProperties.getClientName(),
|
||||||
|
redisProperties.isSsl(), redisProperties.getSslSocketFactory(),
|
||||||
|
redisProperties.getSslParameters(), redisProperties.getHostnameVerifier());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
try {
|
||||||
|
if (pool != null) {
|
||||||
|
pool.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从连接池里取连接(用完连接后必须销毁)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Jedis getResource() {
|
||||||
|
return pool.getResource();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用完后,销毁连接(必须)
|
||||||
|
*
|
||||||
|
* @param jedis
|
||||||
|
*/
|
||||||
|
private void destroyResource(Jedis jedis) {
|
||||||
|
if (jedis == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
jedis.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取数据
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String get(String key) {
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
return jedis.get(key);
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取对象数据(不支持Collection数据类型)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param clazz
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T get(String key, Class<T> clazz) {
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (clazz == null) {
|
||||||
|
logger.warn("Params clazz is null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String value = get(key);
|
||||||
|
if (StringUtils.isBlank(value) || StringUtils.equalsIgnoreCase(value, BLANK_CONTENT)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
T obj = null;
|
||||||
|
try {
|
||||||
|
obj = om.readValue(value, clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Can not unserialize obj to [{}] with string [{}]", clazz.getName(), value);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容(无论key是否存在,均会更新key对应的值)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param obj
|
||||||
|
* @param expireTime 缓存 内容过期时间 (单位:秒) ,若expireTime小于0 则表示该内容不过期
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String set(String key, Object obj, int expireTime) {
|
||||||
|
String value = RedisService.BLANK_CONTENT;
|
||||||
|
if (obj != null) {
|
||||||
|
try {
|
||||||
|
value = RedisService.om.writeValueAsString(obj);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Can not write object to redis:" + obj.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set(key, value, expireTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容(无论key是否存在,均会更新key对应的值)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param expireTime 缓存 内容过期时间 (单位:秒) ,若expireTime小于0 则表示该内容不过期
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String set(String key, String value, int expireTime) {
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
|
||||||
|
logger.warn("Params value is null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
String result = jedis.set(key, value);
|
||||||
|
if (expireTime > 0) {
|
||||||
|
jedis.expire(key, expireTime);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取对象数据(不支持Collection数据类型)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param clazz
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> RedisResult<T> getResult(String key, Class<T> clazz) {
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (clazz == null) {
|
||||||
|
logger.warn("Params clazz is null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
RedisResult<T> redisResult = new RedisResult<T>();
|
||||||
|
|
||||||
|
String value = get(key);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
redisResult.setExist(false);
|
||||||
|
return redisResult;
|
||||||
|
}
|
||||||
|
//到此步,则表明redis中存在key
|
||||||
|
redisResult.setExist(true);
|
||||||
|
if (StringUtils.equalsIgnoreCase(value, BLANK_CONTENT)) {
|
||||||
|
return redisResult;
|
||||||
|
}
|
||||||
|
T obj = null;
|
||||||
|
try {
|
||||||
|
obj = om.readValue(value, clazz);
|
||||||
|
redisResult.setResult(obj);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Can not unserialize obj to [{}] with string [{}]", clazz.getName(), value);
|
||||||
|
//到此步直接视为无值
|
||||||
|
redisResult.setExist(false);
|
||||||
|
}
|
||||||
|
return redisResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key取 Collection 对象数据
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param elementClazz 集合元素类型
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> RedisResult<T> getListResult(String key, Class<T> elementClazz) {
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementClazz == null) {
|
||||||
|
logger.warn("Params elementClazz is null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
RedisResult<T> redisResult = new RedisResult<T>();
|
||||||
|
|
||||||
|
String value = get(key);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
redisResult.setExist(false);
|
||||||
|
return redisResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
//到此步,则表明redis中存在key
|
||||||
|
redisResult.setExist(true);
|
||||||
|
if (StringUtils.equalsIgnoreCase(value, BLANK_CONTENT)) {
|
||||||
|
return redisResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> list = null;
|
||||||
|
try {
|
||||||
|
list = om.readValue(value, getCollectionType(List.class, elementClazz));
|
||||||
|
redisResult.setListResult(list);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Can not unserialize list to [{}] with string [{}]", elementClazz.getName(), value);
|
||||||
|
//到此步直接视为无值
|
||||||
|
redisResult.setExist(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redisResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param obj
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String set(String key, Object obj) {
|
||||||
|
String value = RedisService.BLANK_CONTENT;
|
||||||
|
if (obj != null) {
|
||||||
|
try {
|
||||||
|
value = RedisService.om.writeValueAsString(obj);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Can not write object to redis:" + obj.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> JavaType getCollectionType(Class<? extends Collection> collectionClazz,
|
||||||
|
Class<T> elementClazz) {
|
||||||
|
return om.getTypeFactory().constructCollectionType(collectionClazz, elementClazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容(默认有过期时间 1小时)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String set(String key, String value) {
|
||||||
|
return this.set(key, value, DEFAULT_EXPIRE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入/修改 缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param nxxx 缓存写入值模式 详见 {@link RedisService#NXXX_SET_IF_EXISTS}, {@link RedisService#NXXX_SET_IF_NOT_EXISTS}
|
||||||
|
* @param expx 缓存超时时间单位 详见{@link RedisService#EXPX_SECONDS}, {@link RedisService#EXPX_MILLISECOND}
|
||||||
|
* @param expiredTime 缓存存活时长,必须 大于0
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String set(String key, String value, String nxxx, String expx, long expiredTime) {
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
logger.warn("Params value is null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
return jedis.set(key, value);
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅当redis中不含对应的key时,设定缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param expiredTime 缓存内容过期时间 (单位:秒) ,expireTime必须大于0
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String setnx(String key, String value, long expiredTime) {
|
||||||
|
return this.set(key, value, NXXX_SET_IF_NOT_EXISTS, EXPX_SECONDS, expiredTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅当redis中含有对应的key时,修改缓存内容
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param expiredTime 缓存内容过期时间 (单位:秒) ,expireTime必须大于0
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String setxx(String key, String value, long expiredTime) {
|
||||||
|
return this.set(key, value, NXXX_SET_IF_EXISTS, EXPX_SECONDS, expiredTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key删除缓存
|
||||||
|
*
|
||||||
|
* @param keys
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Long delete(String... keys) {
|
||||||
|
if (keys == null || keys.length == 0) {
|
||||||
|
logger.warn("Params keys is null or 0 length!");
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
return jedis.del(keys);
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断对应的key是否存在
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean exists(String key) {
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
//不接受空值
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
return jedis.exists(key);
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis 加法运算
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Long incrBy(String key, long value) {
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
return jedis.incrBy(key, value);
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设定redis 对应的key的剩余存活时间
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param seconds
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setTTL(String key, int seconds) {
|
||||||
|
if (seconds < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
logger.warn("Params key is blank!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
jedis.expire(key, seconds);
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据通配符表达式查询key值的set,通配符仅支持*
|
||||||
|
*
|
||||||
|
* @param pattern 如 ke6*abc等
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Set<String> keys(String pattern) {
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(pattern)) {
|
||||||
|
logger.warn("Params pattern is blank!");
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
Jedis jedis = this.getResource();
|
||||||
|
try {
|
||||||
|
return jedis.keys(pattern);
|
||||||
|
} finally {
|
||||||
|
this.destroyResource(jedis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转为json字符串。若对象为null,则返回 {@link RedisService#BLANK_CONTENT}
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toJsonString(Object object) {
|
||||||
|
if (object == null) {
|
||||||
|
return BLANK_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((object instanceof Collection) && CollectionUtils.isEmpty((Collection) object)) {
|
||||||
|
return BLANK_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((object instanceof Map) && CollectionUtils.isEmpty((Map) object)) {
|
||||||
|
return BLANK_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return om.writeValueAsString(object);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String makeSerializedString(Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return BLANK_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((value instanceof Collection) && ((Collection) value).size() == 0) {
|
||||||
|
return BLANK_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((value instanceof Map) && ((Map) value).size() == 0) {
|
||||||
|
return BLANK_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return JSON.toJSONString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String put(String cacheName, String key, Object value) {
|
||||||
|
String result = get(cacheName);
|
||||||
|
Map map = new HashMap();
|
||||||
|
if (StringUtils.isNotBlank(result)){
|
||||||
|
map = JSON.parseObject(result, new TypeReference<Map>() {});
|
||||||
|
}
|
||||||
|
map.put(key,value);
|
||||||
|
return set(cacheName,map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String put(String cacheName, String key, Object value, int expireTime) {
|
||||||
|
String result = get(cacheName);
|
||||||
|
Map map = new HashMap();
|
||||||
|
if (StringUtils.isNotBlank(result)){
|
||||||
|
map = JSON.parseObject(result, new TypeReference<Map>() {});
|
||||||
|
}
|
||||||
|
map.put(key,value);
|
||||||
|
return set(cacheName,map,expireTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object get(String cacheName, String key){
|
||||||
|
String result = get(cacheName);
|
||||||
|
if (StringUtils.isNotBlank(result)){
|
||||||
|
Map map = JSON.parseObject(result, new TypeReference<Map>() {});
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,198 @@
|
|||||||
|
package com.rymcu.forest.core.service.security;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.rymcu.forest.core.service.security.annotation.AuthorshipInterceptor;
|
||||||
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
|
import com.rymcu.forest.entity.Article;
|
||||||
|
import com.rymcu.forest.entity.Portfolio;
|
||||||
|
import com.rymcu.forest.enumerate.Module;
|
||||||
|
import com.rymcu.forest.jwt.def.JwtConstants;
|
||||||
|
import com.rymcu.forest.mapper.UserMapper;
|
||||||
|
import com.rymcu.forest.service.ArticleService;
|
||||||
|
import com.rymcu.forest.service.PortfolioService;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
|
import com.rymcu.forest.web.api.exception.ErrorCode;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户修改信息权限
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class AuthorshipAspect {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(AuthorshipAspect.class);
|
||||||
|
|
||||||
|
@Pointcut("@annotation(com.rymcu.forest.core.service.security.annotation.AuthorshipInterceptor)")
|
||||||
|
public void authorshipPointCut() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ArticleService articleService;
|
||||||
|
@Resource
|
||||||
|
private PortfolioService portfolioService;
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户修改信息权限
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @return 方法执行结果
|
||||||
|
* @throws Throwable 调用出错
|
||||||
|
*/
|
||||||
|
@Before(value = "authorshipPointCut()")
|
||||||
|
public void doBefore(JoinPoint joinPoint) throws BaseApiException {
|
||||||
|
logger.info("检查作者身份 start ...");
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
Method method = currentMethod(joinPoint, methodName);
|
||||||
|
AuthorshipInterceptor log = method.getAnnotation(AuthorshipInterceptor.class);
|
||||||
|
if (Objects.nonNull(log)) {
|
||||||
|
boolean isArticle = true;
|
||||||
|
if (Module.PORTFOLIO.equals(log.moduleName())) {
|
||||||
|
isArticle = false;
|
||||||
|
}
|
||||||
|
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||||
|
String idArticle;
|
||||||
|
Long idAuthor = 0l;
|
||||||
|
if (isAjax(request)) {
|
||||||
|
Object[] objects = joinPoint.getArgs();
|
||||||
|
JSONObject jsonObject;
|
||||||
|
if (objects[0] instanceof Integer) {
|
||||||
|
jsonObject = new JSONObject();
|
||||||
|
if (isArticle) {
|
||||||
|
jsonObject.put("idArticle", objects[0].toString());
|
||||||
|
} else {
|
||||||
|
jsonObject.put("idPortfolio", objects[0].toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jsonObject = JSONObject.parseObject(JSON.toJSONString(objects[0]));
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(jsonObject)) {
|
||||||
|
if (isArticle) {
|
||||||
|
idArticle = jsonObject.getString("idArticle");
|
||||||
|
Article article = articleService.findById(idArticle);
|
||||||
|
if (Objects.nonNull(article)) {
|
||||||
|
idAuthor = article.getArticleAuthorId();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
idArticle = jsonObject.getString("idPortfolio");
|
||||||
|
Portfolio portfolio = portfolioService.findById(idArticle);
|
||||||
|
if (Objects.nonNull(portfolio)) {
|
||||||
|
idAuthor = portfolio.getPortfolioAuthorId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Map params = getParams(request);
|
||||||
|
if (params.isEmpty()) {
|
||||||
|
params = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||||
|
} else {
|
||||||
|
params.putAll((Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE));
|
||||||
|
}
|
||||||
|
if (isArticle) {
|
||||||
|
idArticle = (String) params.get("idArticle");
|
||||||
|
Article article = articleService.findById(idArticle);
|
||||||
|
if (Objects.nonNull(article)) {
|
||||||
|
idAuthor = article.getArticleAuthorId();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
idArticle = (String) params.get("idPortfolio");
|
||||||
|
Portfolio portfolio = portfolioService.findById(idArticle);
|
||||||
|
if (Objects.nonNull(portfolio)) {
|
||||||
|
idAuthor = portfolio.getPortfolioAuthorId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (idAuthor > 0) {
|
||||||
|
String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
|
||||||
|
if (StringUtils.isNotBlank(authHeader)) {
|
||||||
|
TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
|
||||||
|
if (Objects.nonNull(tokenUser)) {
|
||||||
|
if (!idAuthor.equals(tokenUser.getIdUser())) {
|
||||||
|
boolean hasPermission = false;
|
||||||
|
if (Module.ARTICLE_TAG.equals(log.moduleName())) {
|
||||||
|
// 判断管理员权限
|
||||||
|
hasPermission = userMapper.hasAdminPermission(tokenUser.getAccount());
|
||||||
|
}
|
||||||
|
if (!hasPermission) {
|
||||||
|
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("检查作者身份 end ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前执行的方法
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @param methodName 方法名称
|
||||||
|
* @return 方法
|
||||||
|
*/
|
||||||
|
private Method currentMethod(JoinPoint joinPoint, String methodName) {
|
||||||
|
/**
|
||||||
|
* 获取目标类的所有方法,找到当前要执行的方法
|
||||||
|
*/
|
||||||
|
Method[] methods = joinPoint.getTarget().getClass().getMethods();
|
||||||
|
Method resultMethod = null;
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.getName().equals(methodName)) {
|
||||||
|
resultMethod = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getParams(HttpServletRequest request) {
|
||||||
|
Map<String, String> paramsMap = new HashMap<>(10);
|
||||||
|
Enumeration<String> paraNames = request.getParameterNames();
|
||||||
|
while (paraNames.hasMoreElements()) {
|
||||||
|
String key = paraNames.nextElement();
|
||||||
|
if ("password".equals(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
paramsMap.put(key, request.getParameter(key));
|
||||||
|
}
|
||||||
|
return paramsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAjax(HttpServletRequest request) {
|
||||||
|
String requestedWith = request.getHeader("x-requested-with");
|
||||||
|
if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String contentType = request.getContentType();
|
||||||
|
return StringUtils.isNotBlank(contentType) && contentType.contains("application/json");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
package com.rymcu.forest.core.service.security;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.rymcu.forest.dto.TokenUser;
|
||||||
|
import com.rymcu.forest.jwt.def.JwtConstants;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
|
import com.rymcu.forest.web.api.exception.ErrorCode;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户修改信息权限
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class SecurityAspect {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(SecurityAspect.class);
|
||||||
|
|
||||||
|
@Pointcut("@annotation(com.rymcu.forest.core.service.security.annotation.SecurityInterceptor)")
|
||||||
|
public void securityPointCut() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户修改信息权限
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @return 方法执行结果
|
||||||
|
* @throws Throwable 调用出错
|
||||||
|
*/
|
||||||
|
@Before(value = "securityPointCut()")
|
||||||
|
public void doBefore(JoinPoint joinPoint) throws BaseApiException {
|
||||||
|
logger.info("检查用户修改信息权限 start ...");
|
||||||
|
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
|
String idUser = "";
|
||||||
|
if (isAjax(request)) {
|
||||||
|
Object[] objects = joinPoint.getArgs();
|
||||||
|
JSONObject jsonObject;
|
||||||
|
if (objects[0] instanceof Integer) {
|
||||||
|
idUser = objects[0].toString();
|
||||||
|
} else {
|
||||||
|
jsonObject = JSONObject.parseObject(JSON.toJSONString(objects[0]));
|
||||||
|
if (Objects.nonNull(jsonObject)) {
|
||||||
|
idUser = jsonObject.getString("idUser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Map params = getParams(request);
|
||||||
|
if (params.isEmpty()) {
|
||||||
|
params = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||||
|
} else {
|
||||||
|
params.putAll((Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE));
|
||||||
|
}
|
||||||
|
idUser = (String) params.get("idUser");
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(idUser)) {
|
||||||
|
String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
|
||||||
|
if (StringUtils.isNotBlank(authHeader)) {
|
||||||
|
TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
|
||||||
|
if (Objects.nonNull(tokenUser)) {
|
||||||
|
if (!idUser.equals(tokenUser.getIdUser().toString())) {
|
||||||
|
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
logger.info("检查用户修改信息权限 end ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getParams(HttpServletRequest request) {
|
||||||
|
Map<String, String> paramsMap = new HashMap<>(10);
|
||||||
|
Enumeration<String> paraNames = request.getParameterNames();
|
||||||
|
while (paraNames.hasMoreElements()) {
|
||||||
|
String key = paraNames.nextElement();
|
||||||
|
if ("password".equals(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
paramsMap.put(key, request.getParameter(key));
|
||||||
|
}
|
||||||
|
return paramsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAjax(HttpServletRequest request) {
|
||||||
|
String requestedWith = request.getHeader("x-requested-with");
|
||||||
|
if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String contentType = request.getContentType();
|
||||||
|
return StringUtils.isNotBlank(contentType) && contentType.contains("application/json");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.rymcu.forest.core.service.security.annotation;
|
||||||
|
|
||||||
|
import com.rymcu.forest.enumerate.Module;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2022/1/5 19:46.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface AuthorshipInterceptor {
|
||||||
|
Module moduleName();
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.rymcu.forest.core.service.security.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全拦截器
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface SecurityInterceptor {
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/AnswerDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/AnswerDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AnswerDTO {
|
||||||
|
|
||||||
|
private Integer idSubjectQuestion;
|
||||||
|
|
||||||
|
private String answer;
|
||||||
|
|
||||||
|
private Integer idUser;
|
||||||
|
|
||||||
|
}
|
73
src/main/java/com/rymcu/forest/dto/ArticleDTO.java
Normal file
73
src/main/java/com/rymcu/forest/dto/ArticleDTO.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ArticleDTO {
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticle;
|
||||||
|
/** 文章标题 */
|
||||||
|
private String articleTitle;
|
||||||
|
/** 文章缩略图 */
|
||||||
|
private String articleThumbnailUrl;
|
||||||
|
/** 文章作者id */
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long articleAuthorId;
|
||||||
|
/** 文章作者 */
|
||||||
|
private String articleAuthorName;
|
||||||
|
/** 文章作者头像 */
|
||||||
|
private String articleAuthorAvatarUrl;
|
||||||
|
/** 文章类型 */
|
||||||
|
private String articleType;
|
||||||
|
/** 文章标签 */
|
||||||
|
private String articleTags;
|
||||||
|
/** 浏览总数 */
|
||||||
|
private Integer articleViewCount;
|
||||||
|
/** 预览内容 */
|
||||||
|
private String articlePreviewContent;
|
||||||
|
/** 文章内容 */
|
||||||
|
private String articleContent;
|
||||||
|
/** 文章内容html */
|
||||||
|
private String articleContentHtml;
|
||||||
|
/** 评论总数 */
|
||||||
|
private Integer articleCommentCount;
|
||||||
|
/** 过去时长 */
|
||||||
|
private String timeAgo;
|
||||||
|
/** 文章永久链接 */
|
||||||
|
private String articlePermalink;
|
||||||
|
/** 站内链接 */
|
||||||
|
private String articleLink;
|
||||||
|
/** 文章状态 */
|
||||||
|
private String articleStatus;
|
||||||
|
/** 更新时间 */
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updatedTime;
|
||||||
|
|
||||||
|
private Author articleAuthor;
|
||||||
|
|
||||||
|
private List<ArticleTagDTO> tags;
|
||||||
|
|
||||||
|
private List<PortfolioArticleDTO> portfolios;
|
||||||
|
|
||||||
|
private Integer sortNo;
|
||||||
|
/** 0:非优选1:优选;0 */
|
||||||
|
private String articlePerfect;
|
||||||
|
/** 点赞总数 */
|
||||||
|
private Integer articleThumbsUpCount;
|
||||||
|
/** 赞赏总数 */
|
||||||
|
private Integer articleSponsorCount;
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/ArticleSearchDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/ArticleSearchDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ArticleSearchDTO {
|
||||||
|
|
||||||
|
private String searchText;
|
||||||
|
|
||||||
|
private String topicUri;
|
||||||
|
|
||||||
|
private String tag;
|
||||||
|
|
||||||
|
}
|
35
src/main/java/com/rymcu/forest/dto/ArticleTagDTO.java
Normal file
35
src/main/java/com/rymcu/forest/dto/ArticleTagDTO.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ArticleTagDTO {
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticleTag;
|
||||||
|
|
||||||
|
private Integer idTag;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticle;
|
||||||
|
|
||||||
|
private String tagTitle;
|
||||||
|
|
||||||
|
private String tagUri;
|
||||||
|
|
||||||
|
private String tagDescription;
|
||||||
|
|
||||||
|
private String tagIconPath;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long tagAuthorId;
|
||||||
|
}
|
29
src/main/java/com/rymcu/forest/dto/Author.java
Normal file
29
src/main/java/com/rymcu/forest/dto/Author.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Author {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
|
||||||
|
private String userNickname;
|
||||||
|
|
||||||
|
private String userAccount;
|
||||||
|
|
||||||
|
private String userAvatarURL;
|
||||||
|
|
||||||
|
private String userArticleCount;
|
||||||
|
|
||||||
|
}
|
35
src/main/java/com/rymcu/forest/dto/BankAccountDTO.java
Normal file
35
src/main/java/com/rymcu/forest/dto/BankAccountDTO.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BankAccountDTO {
|
||||||
|
|
||||||
|
private Integer idBankAccount;
|
||||||
|
/** 所属银行 */
|
||||||
|
private Integer idBank;
|
||||||
|
/** 所属银行名称 */
|
||||||
|
private String bankName;
|
||||||
|
/** 银行账户 */
|
||||||
|
private String bankAccount;
|
||||||
|
/** 账户余额 */
|
||||||
|
private BigDecimal accountBalance;
|
||||||
|
/** 账户所有者 */
|
||||||
|
private Integer accountOwner;
|
||||||
|
/** 账户所有者姓名 */
|
||||||
|
private String accountOwnerName;
|
||||||
|
/** 创建时间 */
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
private List<TransactionRecordDTO> transactionRecords;
|
||||||
|
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/BankAccountSearchDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/BankAccountSearchDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BankAccountSearchDTO {
|
||||||
|
/** 所属银行名称 */
|
||||||
|
private String bankName;
|
||||||
|
/** 银行账户 */
|
||||||
|
private String bankAccount;
|
||||||
|
/** 账户所有者姓名 */
|
||||||
|
private String accountOwnerName;
|
||||||
|
|
||||||
|
}
|
33
src/main/java/com/rymcu/forest/dto/BankDTO.java
Normal file
33
src/main/java/com/rymcu/forest/dto/BankDTO.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BankDTO {
|
||||||
|
|
||||||
|
private Integer idBank;
|
||||||
|
/** 银行名称 */
|
||||||
|
private String bankName;
|
||||||
|
/** 银行负责人 */
|
||||||
|
private Integer bankOwner;
|
||||||
|
/** 银行负责人 */
|
||||||
|
private String bankOwnerName;
|
||||||
|
/** 银行账户 */
|
||||||
|
private String bankAccount;
|
||||||
|
/** 账户余额 */
|
||||||
|
private BigDecimal accountBalance;
|
||||||
|
/** 银行描述 */
|
||||||
|
private String bankDescription;
|
||||||
|
/** 创建人 */
|
||||||
|
private Integer createdBy;
|
||||||
|
/** 创建时间 */
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createdTime;
|
||||||
|
}
|
19
src/main/java/com/rymcu/forest/dto/ChangeEmailDTO.java
Normal file
19
src/main/java/com/rymcu/forest/dto/ChangeEmailDTO.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ChangeEmailDTO {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
}
|
47
src/main/java/com/rymcu/forest/dto/CommentDTO.java
Normal file
47
src/main/java/com/rymcu/forest/dto/CommentDTO.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CommentDTO {
|
||||||
|
private Integer idComment;
|
||||||
|
/** 评论内容 */
|
||||||
|
private String commentContent;
|
||||||
|
/** 作者 id */
|
||||||
|
private Integer commentAuthorId;
|
||||||
|
/** 文章 id */
|
||||||
|
private Integer commentArticleId;
|
||||||
|
/** 锚点 url */
|
||||||
|
private String commentSharpUrl;
|
||||||
|
/** 父评论 id */
|
||||||
|
private Integer commentOriginalCommentId;
|
||||||
|
/** 父评论作者头像 */
|
||||||
|
private String commentOriginalAuthorThumbnailURL;
|
||||||
|
/** 父评论作者昵称 */
|
||||||
|
private String commentOriginalAuthorNickname;
|
||||||
|
/** 父评论作者昵称 */
|
||||||
|
private String commentOriginalContent;
|
||||||
|
/** 状态 */
|
||||||
|
private String commentStatus;
|
||||||
|
/** 0:公开回帖,1:匿名回帖 */
|
||||||
|
private String commentAnonymous;
|
||||||
|
/** 回帖计数 */
|
||||||
|
private Integer commentReplyCount;
|
||||||
|
/** 0:所有人可见,1:仅楼主和自己可见 */
|
||||||
|
private String commentVisible;
|
||||||
|
/** 创建时间 */
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
private Author commenter;
|
||||||
|
|
||||||
|
private String timeAgo;
|
||||||
|
|
||||||
|
private String articleTitle;
|
||||||
|
}
|
13
src/main/java/com/rymcu/forest/dto/ForgetPasswordDTO.java
Normal file
13
src/main/java/com/rymcu/forest/dto/ForgetPasswordDTO.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ForgetPasswordDTO {
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/LabelModel.java
Normal file
17
src/main/java/com/rymcu/forest/dto/LabelModel.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LabelModel implements Serializable {
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
}
|
15
src/main/java/com/rymcu/forest/dto/LinkToImageUrlDTO.java
Normal file
15
src/main/java/com/rymcu/forest/dto/LinkToImageUrlDTO.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LinkToImageUrlDTO {
|
||||||
|
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
}
|
30
src/main/java/com/rymcu/forest/dto/MenuDTO.java
Normal file
30
src/main/java/com/rymcu/forest/dto/MenuDTO.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class MenuDTO {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
private String parentName;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Long sort;
|
||||||
|
|
||||||
|
private String href;
|
||||||
|
|
||||||
|
private String menuType;
|
||||||
|
|
||||||
|
private String permission;
|
||||||
|
|
||||||
|
private String remarks;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
}
|
24
src/main/java/com/rymcu/forest/dto/NotificationDTO.java
Normal file
24
src/main/java/com/rymcu/forest/dto/NotificationDTO.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.rymcu.forest.entity.Notification;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class NotificationDTO extends Notification {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idNotification;
|
||||||
|
|
||||||
|
private String dataTitle;
|
||||||
|
|
||||||
|
private String dataUrl;
|
||||||
|
|
||||||
|
private Author author;
|
||||||
|
|
||||||
|
}
|
31
src/main/java/com/rymcu/forest/dto/PortfolioArticleDTO.java
Normal file
31
src/main/java/com/rymcu/forest/dto/PortfolioArticleDTO.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PortfolioArticleDTO {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idPortfolio;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticle;
|
||||||
|
|
||||||
|
private String headImgUrl;
|
||||||
|
|
||||||
|
private String portfolioTitle;
|
||||||
|
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
|
private List<ArticleDTO> articles;
|
||||||
|
|
||||||
|
}
|
38
src/main/java/com/rymcu/forest/dto/PortfolioDTO.java
Normal file
38
src/main/java/com/rymcu/forest/dto/PortfolioDTO.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PortfolioDTO {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idPortfolio;
|
||||||
|
/** 作品集头像 */
|
||||||
|
private String headImgUrl;
|
||||||
|
/** 作品集作者 */
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long portfolioAuthorId;
|
||||||
|
/** 作品集作者 */
|
||||||
|
private String portfolioAuthorName;
|
||||||
|
/** 作品集作者头像 */
|
||||||
|
private String portfolioAuthorAvatarUrl;
|
||||||
|
/** 作品集名称 */
|
||||||
|
private String portfolioTitle;
|
||||||
|
/** 作品集介绍 */
|
||||||
|
private String portfolioDescription;
|
||||||
|
/** 更新时间 */
|
||||||
|
private Date updatedTime;
|
||||||
|
/** 过去时长 */
|
||||||
|
private String timeAgo;
|
||||||
|
|
||||||
|
private Author portfolioAuthor;
|
||||||
|
|
||||||
|
private Integer articleNumber;
|
||||||
|
|
||||||
|
}
|
23
src/main/java/com/rymcu/forest/dto/ProductDTO.java
Normal file
23
src/main/java/com/rymcu/forest/dto/ProductDTO.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.rymcu.forest.entity.Product;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2022/6/21 9:38.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
* @packageName com.rymcu.forest.dto
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ProductDTO extends Product {
|
||||||
|
/**
|
||||||
|
* 文章内容
|
||||||
|
*/
|
||||||
|
private String productContent;
|
||||||
|
/**
|
||||||
|
* 文章内容html
|
||||||
|
*/
|
||||||
|
private String productContentHtml;
|
||||||
|
}
|
19
src/main/java/com/rymcu/forest/dto/RoleDTO.java
Normal file
19
src/main/java/com/rymcu/forest/dto/RoleDTO.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RoleDTO {
|
||||||
|
|
||||||
|
// id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
// 名称
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
// 英文名称
|
||||||
|
private String inputCode;
|
||||||
|
|
||||||
|
// 角色授权菜单ids
|
||||||
|
private String menuIds;
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/SearchModel.java
Normal file
17
src/main/java/com/rymcu/forest/dto/SearchModel.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SearchModel {
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
}
|
27
src/main/java/com/rymcu/forest/dto/TokenUser.java
Normal file
27
src/main/java/com/rymcu/forest/dto/TokenUser.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TokenUser {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
|
||||||
|
private String account;
|
||||||
|
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
private String avatarType;
|
||||||
|
|
||||||
|
private String avatarUrl;
|
||||||
|
|
||||||
|
private Integer weights;
|
||||||
|
|
||||||
|
}
|
36
src/main/java/com/rymcu/forest/dto/TransactionRecordDTO.java
Normal file
36
src/main/java/com/rymcu/forest/dto/TransactionRecordDTO.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TransactionRecordDTO {
|
||||||
|
|
||||||
|
private Integer idTransactionRecord;
|
||||||
|
/** 交易流水号 */
|
||||||
|
private String transactionNo;
|
||||||
|
/** 款项 */
|
||||||
|
private String funds;
|
||||||
|
/** 交易发起方 */
|
||||||
|
private String formBankAccount;
|
||||||
|
/** 交易发起方 */
|
||||||
|
private BankAccountDTO formBankAccountInfo;
|
||||||
|
/** 交易收款方 */
|
||||||
|
private String toBankAccount;
|
||||||
|
/** 交易收款方 */
|
||||||
|
private BankAccountDTO toBankAccountInfo;
|
||||||
|
/** 交易金额 */
|
||||||
|
private BigDecimal money;
|
||||||
|
/** 交易类型 */
|
||||||
|
private String transactionType;
|
||||||
|
/** 交易时间 */
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date transactionTime;
|
||||||
|
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/UpdatePasswordDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/UpdatePasswordDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UpdatePasswordDTO {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
}
|
26
src/main/java/com/rymcu/forest/dto/UserDTO.java
Normal file
26
src/main/java/com/rymcu/forest/dto/UserDTO.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserDTO {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
|
||||||
|
private String account;
|
||||||
|
|
||||||
|
private String avatarType;
|
||||||
|
|
||||||
|
private String avatarUrl;
|
||||||
|
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
private String bgImgUrl;
|
||||||
|
}
|
53
src/main/java/com/rymcu/forest/dto/UserInfoDTO.java
Normal file
53
src/main/java/com/rymcu/forest/dto/UserInfoDTO.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserInfoDTO implements Serializable {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
|
||||||
|
private String account;
|
||||||
|
|
||||||
|
private String avatarType;
|
||||||
|
|
||||||
|
private String avatarUrl;
|
||||||
|
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private String roleIds;
|
||||||
|
|
||||||
|
private String sex;
|
||||||
|
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm")
|
||||||
|
private Date lastLoginTime;
|
||||||
|
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm")
|
||||||
|
private Date lastOnlineTime;
|
||||||
|
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
private Integer onlineStatus;
|
||||||
|
|
||||||
|
private String bgImgUrl;
|
||||||
|
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/UserRegisterInfoDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/UserRegisterInfoDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserRegisterInfoDTO {
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
}
|
12
src/main/java/com/rymcu/forest/dto/UserSearchDTO.java
Normal file
12
src/main/java/com/rymcu/forest/dto/UserSearchDTO.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserSearchDTO {
|
||||||
|
|
||||||
|
private String nickname;
|
||||||
|
}
|
22
src/main/java/com/rymcu/forest/dto/admin/Dashboard.java
Normal file
22
src/main/java/com/rymcu/forest/dto/admin/Dashboard.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package com.rymcu.forest.dto.admin;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Dashboard {
|
||||||
|
|
||||||
|
private Integer countUserNum;
|
||||||
|
|
||||||
|
private Integer newUserNum;
|
||||||
|
|
||||||
|
private Integer countArticleNum;
|
||||||
|
|
||||||
|
private Integer newArticleNum;
|
||||||
|
|
||||||
|
private Integer countViewNum;
|
||||||
|
|
||||||
|
private Integer todayViewNum;
|
||||||
|
}
|
15
src/main/java/com/rymcu/forest/dto/admin/DashboardData.java
Normal file
15
src/main/java/com/rymcu/forest/dto/admin/DashboardData.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package com.rymcu.forest.dto.admin;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DashboardData {
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
private Integer value;
|
||||||
|
|
||||||
|
}
|
26
src/main/java/com/rymcu/forest/dto/admin/TagDTO.java
Normal file
26
src/main/java/com/rymcu/forest/dto/admin/TagDTO.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.rymcu.forest.dto.admin;
|
||||||
|
|
||||||
|
import com.rymcu.forest.dto.Author;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TagDTO {
|
||||||
|
|
||||||
|
private Integer idTag;
|
||||||
|
|
||||||
|
private String tagTitle;
|
||||||
|
|
||||||
|
private String tagUri;
|
||||||
|
|
||||||
|
private String tagDescription;
|
||||||
|
|
||||||
|
private String tagIconPath;
|
||||||
|
|
||||||
|
private Integer tagAuthorId;
|
||||||
|
|
||||||
|
private Author tagAuthor;
|
||||||
|
|
||||||
|
}
|
29
src/main/java/com/rymcu/forest/dto/admin/TopicDTO.java
Normal file
29
src/main/java/com/rymcu/forest/dto/admin/TopicDTO.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package com.rymcu.forest.dto.admin;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TopicDTO {
|
||||||
|
|
||||||
|
private Integer idTopic;
|
||||||
|
|
||||||
|
private String topicTitle;
|
||||||
|
|
||||||
|
private String topicUri;
|
||||||
|
|
||||||
|
private String topicIconPath;
|
||||||
|
|
||||||
|
private String topicDescription;
|
||||||
|
|
||||||
|
private String topicStatus;
|
||||||
|
|
||||||
|
private Integer topicTagCount;
|
||||||
|
|
||||||
|
private List<TagDTO> tags;
|
||||||
|
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/admin/TopicTagDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/admin/TopicTagDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto.admin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TopicTagDTO {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idTopic;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idTag;
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/admin/UserRoleDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/admin/UserRoleDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto.admin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserRoleDTO {
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idRole;
|
||||||
|
}
|
17
src/main/java/com/rymcu/forest/dto/baidu/TagNlpDTO.java
Normal file
17
src/main/java/com/rymcu/forest/dto/baidu/TagNlpDTO.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.dto.baidu;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TagNlpDTO {
|
||||||
|
|
||||||
|
private BigDecimal score;
|
||||||
|
|
||||||
|
private String tag;
|
||||||
|
|
||||||
|
}
|
58
src/main/java/com/rymcu/forest/entity/Article.java
Normal file
58
src/main/java/com/rymcu/forest/entity/Article.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(name = "forest_article")
|
||||||
|
public class Article implements Serializable,Cloneable {
|
||||||
|
/** 主键 */
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(generator = "JDBC")
|
||||||
|
@Column(name = "id")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticle;
|
||||||
|
/** 文章标题 */
|
||||||
|
private String articleTitle;
|
||||||
|
/** 文章缩略图 */
|
||||||
|
private String articleThumbnailUrl;
|
||||||
|
/** 文章作者id */
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long articleAuthorId;
|
||||||
|
/** 文章类型 */
|
||||||
|
private String articleType;
|
||||||
|
/** 文章标签 */
|
||||||
|
private String articleTags;
|
||||||
|
/** 浏览总数 */
|
||||||
|
private Integer articleViewCount;
|
||||||
|
/** 预览内容 */
|
||||||
|
private String articlePreviewContent;
|
||||||
|
/** 评论总数 */
|
||||||
|
private Integer articleCommentCount;
|
||||||
|
/** 0:非优选1:优选; */
|
||||||
|
private String articlePerfect;
|
||||||
|
/** 文章永久链接 */
|
||||||
|
private String articlePermalink;
|
||||||
|
/** 站内链接 */
|
||||||
|
private String articleLink;
|
||||||
|
/** 创建时间 */
|
||||||
|
private Date createdTime;
|
||||||
|
/** 更新时间 */
|
||||||
|
private Date updatedTime;
|
||||||
|
/** 文章状态 */
|
||||||
|
private String articleStatus;
|
||||||
|
/** 点赞总数 */
|
||||||
|
private Integer articleThumbsUpCount;
|
||||||
|
/** 赞赏总数 */
|
||||||
|
private Integer articleSponsorCount;
|
||||||
|
}
|
33
src/main/java/com/rymcu/forest/entity/ArticleContent.java
Normal file
33
src/main/java/com/rymcu/forest/entity/ArticleContent.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(name = "forest_article_content")
|
||||||
|
public class ArticleContent {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(generator = "JDBC")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticle;
|
||||||
|
|
||||||
|
private String articleContent;
|
||||||
|
|
||||||
|
private String articleContentHtml;
|
||||||
|
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
private Date updatedTime;
|
||||||
|
|
||||||
|
}
|
41
src/main/java/com/rymcu/forest/entity/ArticleThumbsUp.java
Normal file
41
src/main/java/com/rymcu/forest/entity/ArticleThumbsUp.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(name="forest_article_thumbs_up")
|
||||||
|
public class ArticleThumbsUp implements Serializable, Cloneable {
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(generator = "JDBC")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticleThumbsUp;
|
||||||
|
/**
|
||||||
|
* 文章表主键
|
||||||
|
*/
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idArticle;
|
||||||
|
/**
|
||||||
|
* 用户表主键
|
||||||
|
*/
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idUser;
|
||||||
|
/**
|
||||||
|
* 点赞时间
|
||||||
|
*/
|
||||||
|
private Date thumbsUpTime;
|
||||||
|
}
|
40
src/main/java/com/rymcu/forest/entity/Bank.java
Normal file
40
src/main/java/com/rymcu/forest/entity/Bank.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Table(name = "forest_bank")
|
||||||
|
@Data
|
||||||
|
public class Bank {
|
||||||
|
|
||||||
|
/** 主键 */
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(generator = "JDBC")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idBank;
|
||||||
|
/** 银行名称 */
|
||||||
|
private String bankName;
|
||||||
|
/** 银行负责人 */
|
||||||
|
private Long bankOwner;
|
||||||
|
/** 银行描述 */
|
||||||
|
private String bankDescription;
|
||||||
|
/** 创建人 */
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long createdBy;
|
||||||
|
/** 创建时间 */
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
}
|
42
src/main/java/com/rymcu/forest/entity/BankAccount.java
Normal file
42
src/main/java/com/rymcu/forest/entity/BankAccount.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行账户
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Table(name = "forest_bank_account")
|
||||||
|
@Data
|
||||||
|
public class BankAccount {
|
||||||
|
/** 主键 */
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(generator = "JDBC")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idBankAccount;
|
||||||
|
/** 所属银行 */
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idBank;
|
||||||
|
/** 银行账户 */
|
||||||
|
private String bankAccount;
|
||||||
|
/** 账户余额 */
|
||||||
|
private BigDecimal accountBalance;
|
||||||
|
/** 账户所有者 */
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long accountOwner;
|
||||||
|
/** 创建时间 */
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createdTime;
|
||||||
|
/** 账户类型 */
|
||||||
|
private String accountType;
|
||||||
|
}
|
25
src/main/java/com/rymcu/forest/entity/BaseDO.java
Normal file
25
src/main/java/com/rymcu/forest/entity/BaseDO.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础DO类,提供toString快方法
|
||||||
|
*
|
||||||
|
* @author liwei
|
||||||
|
* @date 2015/6/16
|
||||||
|
*/
|
||||||
|
public class BaseDO implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -1394589131426860408L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
64
src/main/java/com/rymcu/forest/entity/Comment.java
Normal file
64
src/main/java/com/rymcu/forest/entity/Comment.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(name="forest_comment")
|
||||||
|
public class Comment implements Serializable,Cloneable {
|
||||||
|
/** 主键 */
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(generator = "JDBC")
|
||||||
|
@Column(name = "id")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long idComment;
|
||||||
|
/** 评论内容 */
|
||||||
|
@Column(name = "comment_content")
|
||||||
|
private String commentContent;
|
||||||
|
/** 作者 id */
|
||||||
|
@Column(name = "comment_author_id")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long commentAuthorId;
|
||||||
|
/** 文章 id */
|
||||||
|
@Column(name = "comment_article_id")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long commentArticleId;
|
||||||
|
/** 锚点 url */
|
||||||
|
@Column(name = "comment_sharp_url")
|
||||||
|
private String commentSharpUrl;
|
||||||
|
/** 父评论 id */
|
||||||
|
@Column(name = "comment_original_comment_id")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long commentOriginalCommentId;
|
||||||
|
/** 状态 */
|
||||||
|
@Column(name = "comment_status")
|
||||||
|
private String commentStatus;
|
||||||
|
/** 评论 IP */
|
||||||
|
@Column(name = "comment_ip")
|
||||||
|
private String commentIP;
|
||||||
|
/** User-Agent */
|
||||||
|
@Column(name = "comment_ua")
|
||||||
|
private String commentUA;
|
||||||
|
/** 0:公开回帖,1:匿名回帖 */
|
||||||
|
@Column(name = "comment_anonymous")
|
||||||
|
private String commentAnonymous;
|
||||||
|
/** 回帖计数 */
|
||||||
|
@Column(name = "comment_reply_count")
|
||||||
|
private Integer commentReplyCount;
|
||||||
|
/** 0:所有人可见,1:仅楼主和自己可见 */
|
||||||
|
@Column(name = "comment_visible")
|
||||||
|
private String commentVisible;
|
||||||
|
/** 创建时间 */
|
||||||
|
@Column(name = "created_time")
|
||||||
|
private Date createdTime;
|
||||||
|
}
|
32
src/main/java/com/rymcu/forest/entity/CurrencyIssue.java
Normal file
32
src/main/java/com/rymcu/forest/entity/CurrencyIssue.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package com.rymcu.forest.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 货币发行记录
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Table(name = "forest_currency_issue")
|
||||||
|
@Data
|
||||||
|
public class CurrencyIssue {
|
||||||
|
/** 主键 */
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(generator = "JDBC")
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long id;
|
||||||
|
/** 发行数额 */
|
||||||
|
private BigDecimal issueValue;
|
||||||
|
/** 发行人 */
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||||
|
private Long createdBy;
|
||||||
|
/** 发行时间 */
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user