Changes
This commit is contained in:
commit
8bf450c2a3
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
.idea
|
||||
target
|
||||
out
|
||||
*.class
|
||||
*.iml
|
||||
web/node_modules
|
||||
nginx/nginx.exe
|
||||
nginx/temp
|
||||
nginx/logs
|
||||
nginx/docs
|
||||
nginx/contrib
|
||||
nginx/auto
|
||||
nginx/man
|
||||
nginx/src
|
||||
nginx/CHANGES
|
||||
nginx/CHANGES.ru
|
||||
nginx/configure
|
||||
nginx/LICENSE
|
||||
nginx/README
|
||||
filesave
|
203
LICENSE
Normal file
203
LICENSE
Normal file
@ -0,0 +1,203 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2022 xinsin
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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
|
||||
|
||||
http://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.
|
111
README.md
Normal file
111
README.md
Normal file
@ -0,0 +1,111 @@
|
||||
<div align="center"><img alt="Logo" height="128" src="web/src/assets/logo.png" width="128"/></div>
|
||||
|
||||
<h2 align="center">🌟项目名称: WitsTalk</h2>
|
||||
<h5 align="center">一个能在网页语音的项目.</h5>
|
||||
<h5 align="center">🚧 WitsTalk还在开发状态下,请勿当作主力使用.</h5>
|
||||
|
||||
<div align="center">
|
||||
<img alt="GitHub" src="https://img.shields.io/github/license/xin-sin/WitsTalk?style=for-the-badge">
|
||||
<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/xin-sin/WitsTalk/Experimental-UI?style=for-the-badge">
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
<img src="https://img.shields.io/badge/Node-%3E%3Dv14.18.1-green">
|
||||
<img src="https://img.shields.io/badge/Vue-v3.0-blue">
|
||||
<img src="https://img.shields.io/badge/yarn-v1.22.19-yellow">
|
||||
<img src="https://img.shields.io/badge/Java-%3E%3Dv1.8-orange">
|
||||
<img src="https://img.shields.io/badge/SPRING%20BOOT-v2.7-green">
|
||||
<img src="https://img.shields.io/badge/Nety-v4.1.86.Final-lightgrey">
|
||||
|
||||
</div>
|
||||
|
||||
## ✨ WitsTalk是什么项目?
|
||||
- `WitsTalk`是我们项目团队在2021/12/11制作的开源项目,项目的构思是在群语音的时候发现了一些缺点,才开发此项目.
|
||||
- 实现在语音聊天中群员可以调节任何群员的`输出音量`以及自己的`输入音量`.
|
||||
- 管理员拥有最高权限,可以开关群员的`麦克风`,也可以调节群员的`输入音量`. (...暂定是这些功能)
|
||||
- 项目的初衷是给Minecraft玩家一个更舒服的语音环境,更好的交流环境.
|
||||
|
||||
## 💡️ WitsTalk该如何使用?
|
||||
- ~~由于该项目还在开发中,暂不提供使用方式,只提供开发方法~~
|
||||
- 一开完毕将提供完整的`使用文档`和`release`
|
||||
|
||||
## ✏️ 如何向WitsTalk提交代码?
|
||||
- 1.Fork`WitsTalk`
|
||||
- 2.维护代码~
|
||||
- 3.请遵守以下提交格式:
|
||||
- `🚧 Fix`,`➕ Feat`,`🔨 Refactor`,`📝 Docs`,`✨ Style`,`🍱 Perf`,`🔧 Test`,`⚡️ Chore`,`🐛 Bug`
|
||||
- 4.提交到`主仓库`的修改的`相应分支`.
|
||||
|
||||
## ✅ 如何发送Issues?
|
||||
- 请遵守以下提交格式:
|
||||
- `🐛 Bug`,`✨ Style`,`🎨 Proposai`.
|
||||
|
||||
## 👥 本项目开发人员
|
||||
- `[UI设计、前端]Mo_Yi` `[后端、前端]xinxin` `[后端、前端]wzp`
|
||||
- [Dongyifengs 的 GitHub](https://github.com/Dongyifengs)
|
||||
- [XinSin-top 的 GitHub](https://github.com/xin-sin)
|
||||
- [Wzp-2008 的 GitHub](https://github.com/Wzp-2008)
|
||||
|
||||
## ⚖️ 开源协议
|
||||
- 本项目是面向大众的,所以我们会进行开源,请遵循相关开源协议 [Apache License 2.0](https://github.com/XinSin-top/witsTalk/blob/main/LICENSE) 的规则.
|
||||
- 众人拾柴火焰高,开源需要依靠大家的努力,请自觉遵守开源协议,弘扬开源精神,共建开源社区!
|
||||
|
||||
## 🍀 鸣谢
|
||||
<div align="center"><img alt="Logo" height="256" src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png?_gl=1*avq98w*_ga*NjQ5OTM0MzUxLjE2NDY1NTIyMzQ.*_ga_V0XZL7QHEB*MTY0Njk2NjY2Mi4zLjAuMTY0Njk2NjY2Mi4w" width="256"/></div>
|
||||
|
||||
|
||||
## 🧑💻如何开发?
|
||||
- 1.使用`git clone https://github.com/xin-sin/witsTalk.git` 下载我们的项目
|
||||
- 2.我们建议您使用`idea`来进行开发,那样将会为您省去很多配置环境时间
|
||||
- 3.在数据库中创建`user`表
|
||||
|
||||
``` mysql
|
||||
CREATE TABLE `user` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户表id',
|
||||
`username` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户表用户名',
|
||||
`password` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户表密码',
|
||||
`auth` enum('admin','user') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'user' COMMENT '用户表用户权限',
|
||||
`online` tinyint(1) NOT NULL DEFAULT 0 COMMENT '用户表用户是否在线',
|
||||
`last_login` datetime NULL DEFAULT NULL COMMENT '用户表用户最后上线时间',
|
||||
`base64` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '用户表用户头像',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `username`(`username`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
```
|
||||
- 4.在数据库中创建`message`表
|
||||
``` mysql
|
||||
CREATE TABLE `message` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '消息表id',
|
||||
`content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '消息表消息内容',
|
||||
`sender` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '消息表发送者',
|
||||
`recall` tinyint(1) UNSIGNED ZEROFILL NOT NULL DEFAULT 0 COMMENT '消息表是否撤回',
|
||||
`sendtime` datetime NOT NULL COMMENT '消息表消息发送时间',
|
||||
`type` enum('text','img') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'text' COMMENT '消息表消息类型',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `sender`(`sender`) USING BTREE,
|
||||
CONSTRAINT `message_ibfk_1` FOREIGN KEY (`sender`) REFERENCES `witstalk`.`user` (`username`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
```
|
||||
- 5.在数据库中创建`file`表
|
||||
``` mysql
|
||||
CREATE TABLE `file` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文件表id',
|
||||
`size` double NOT NULL COMMENT '文件表文件大小',
|
||||
`name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件表文件名',
|
||||
`md5` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件表文件md5',
|
||||
`uploadTime` datetime NOT NULL COMMENT '文件表文件上传时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
```
|
||||
- 7.调整每一个模块的数据库`url`
|
||||
- 8.使用`maven`来下载后端项目依赖
|
||||
- 9.检查`mysql`数据库版本,并更改`pom.xml`中`JDBC`依赖版本
|
||||
- 10.使用`npm install`下载前端项目依赖
|
||||
- 11.(可选).配置`nginx`反向代理,和端口号
|
||||
- 12.启动前端项目`npm run dev`,启动nginx,启动后端项目:(还用我教吗?-_-):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
291
http.md
Normal file
291
http.md
Normal file
@ -0,0 +1,291 @@
|
||||
# 该文件将列出所有接口以及使用
|
||||
|
||||
## user模块
|
||||
### 用户登录
|
||||
- url:`/user/api/login`
|
||||
- method:`post`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|----------|------|-----|
|
||||
| username | √ | 用户名 |
|
||||
| password | √ | 密码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"username":"admin",
|
||||
"password":"21232f297a57a5a743894a0e4a801fc3",
|
||||
"//":"password是前端MD5加密后"
|
||||
}
|
||||
~~~
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|----------|------|
|
||||
| canLogin | 是否成功 |
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"canLogin":true,
|
||||
"status":200,
|
||||
"//": "登陆成功后会将token写在请求头中,以后每次请求需要携带token进行验证"
|
||||
|
||||
}
|
||||
~~~
|
||||
|
||||
### 添加用户
|
||||
- url:`/user/api/adduser`
|
||||
- method:`post`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|----------|------|----------|
|
||||
| username | √ | 用户名 |
|
||||
| password | √ | 密码 |
|
||||
| auth | √ | 权限 |
|
||||
| base64 | √ | 头像base64 |
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"username":"user",
|
||||
"password":"21232f297a57a5a743894a0e4a801fc3",
|
||||
"auth": "user",
|
||||
"base64": "去头的base64",
|
||||
"//":"password是前端MD5加密后",
|
||||
"/*": "base64是去除{data:image/png;base64,}"
|
||||
}
|
||||
~~~
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|-----|
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"status":200
|
||||
}
|
||||
~~~
|
||||
|
||||
### 修改密码
|
||||
- url:`/user/api/changepassword`
|
||||
- method:`post`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|----------|------|-----|
|
||||
| username | √ | 用户名 |
|
||||
| password | √ | 密码 |
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"username":"user",
|
||||
"password":"21232f297a57a5a743894a0e4a801fc3",
|
||||
"//":"password是前端MD5加密后"
|
||||
}
|
||||
~~~
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|-----|
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"status":200
|
||||
}
|
||||
~~~
|
||||
|
||||
### 修改头像
|
||||
- url:`/user/api/setHeadPortrait`
|
||||
- method:`post`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|----------|------|--------|
|
||||
| username | √ | 用户名 |
|
||||
| base64 | √ | base64 |
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"username":"user",
|
||||
"base64": "去头的base64"
|
||||
}
|
||||
~~~
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|-----|
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"status":200
|
||||
}
|
||||
~~~
|
||||
|
||||
### 获取头像
|
||||
- url:`/user/api/getUserHeadPortrait`
|
||||
- method:`get`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|----------|------|-----|
|
||||
| username | √ | 用户名 |
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"username":"user"
|
||||
}
|
||||
~~~
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|--------|
|
||||
| data | base64 |
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"data": "去头的base64",
|
||||
"status":200
|
||||
}
|
||||
~~~
|
||||
|
||||
### 获取在线人数
|
||||
- url:`/user/api/getOnlineUser`
|
||||
- method:`get`
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|------|
|
||||
| data | 在线用户 |
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"data": "countUser",
|
||||
"status":200
|
||||
}
|
||||
~~~
|
||||
|
||||
## fileTransfer模块
|
||||
|
||||
### 文件上传
|
||||
- url:`/file/api/fileUpload`
|
||||
- method:`post`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|------|------|-----|
|
||||
| file | √ | 文件 |
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"file":"file"
|
||||
}
|
||||
~~~
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|-------|
|
||||
| data | 文件md5 |
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"data": "md5",
|
||||
"status":200
|
||||
}
|
||||
~~~
|
||||
|
||||
### 获取文件名字
|
||||
- url:`/file/api/getName`
|
||||
- method:`get`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|------|------|--------|
|
||||
| md5 | √ | 文件MD5值 |
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|------|
|
||||
| data | 文件名字 |
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"data": "文件名字",
|
||||
"status":200
|
||||
}
|
||||
~~~
|
||||
|
||||
### 下载文件
|
||||
- url:`/file/api/downloadFile`
|
||||
- method:`get`
|
||||
- requestParameter:
|
||||
|
||||
| 参数名称 | 是否必须 | 注释 |
|
||||
|----------|------|--------|
|
||||
| md5 | √ | 文件MD5值 |
|
||||
| filename | √ | 文件名字 |
|
||||
| token | √ | token |
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|----------------|-----|
|
||||
| ResponseEntity | 文件流 |
|
||||
|
||||
### 获取全部文件名字
|
||||
- url:`/file/api/getAllFileNames`
|
||||
- method:`post`
|
||||
|
||||
- responseParameter:
|
||||
|
||||
| 参数名称 | 注释 |
|
||||
|--------|--------|
|
||||
| data | 全部文件名字 |
|
||||
| status | 状态码 |
|
||||
|
||||
- example:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"data": "全部文件名字",
|
||||
"status":200
|
||||
}
|
||||
~~~
|
78
lib-chat/pom.xml
Normal file
78
lib-chat/pom.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>witsTalk</artifactId>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lib-chat</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<artifactId>lib-utils</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!--netty框架依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.86.Final</version>
|
||||
</dependency>
|
||||
<!--spring-boot mybatis依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--druid连接池依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.2.9</version>
|
||||
</dependency>
|
||||
|
||||
<!--mysqlJDBC依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<!--spring-boot web模块-->
|
||||
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<!--<directory>..\target</directory>-->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<!--suppress MavenModelInspection -->
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
44
lib-chat/src/main/java/cn/wzpmc/ChatFrameHandler.java
Normal file
44
lib-chat/src/main/java/cn/wzpmc/ChatFrameHandler.java
Normal file
@ -0,0 +1,44 @@
|
||||
package cn.wzpmc;
|
||||
import cn.wzpmc.services.ChatCommandHandler;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.xinsin.utils.NettyUtils;
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ChatFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||
private static NettyUtils<ChatCommandHandler> commandHandler = null;
|
||||
|
||||
public static void setCommandHandler(ConfigurableApplicationContext configurableApplicationContext) {
|
||||
if(ChatFrameHandler.commandHandler == null){
|
||||
ChatFrameHandler.commandHandler = new NettyUtils<>(ChatCommandHandler.class, configurableApplicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext channelHandlerContext) {
|
||||
commandHandler.handlerJoin(channelHandlerContext);
|
||||
}
|
||||
@Override
|
||||
public void handlerRemoved(ChannelHandlerContext channelHandlerContext) {
|
||||
commandHandler.handlerClose(channelHandlerContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable cause) {
|
||||
commandHandler.handlerError(channelHandlerContext,cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) {
|
||||
commandHandler.handler(channelHandlerContext, textWebSocketFrame);
|
||||
}
|
||||
}
|
43
lib-chat/src/main/java/cn/wzpmc/ChatHandler.java
Normal file
43
lib-chat/src/main/java/cn/wzpmc/ChatHandler.java
Normal file
@ -0,0 +1,43 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
public class ChatHandler extends ChannelInitializer<SocketChannel> {
|
||||
private final ChatFrameHandler chatFrameHandler;
|
||||
public ChatHandler(ChatFrameHandler chatFrameHandler){
|
||||
this.chatFrameHandler = chatFrameHandler;
|
||||
}
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socket){
|
||||
//获取pipeline
|
||||
ChannelPipeline pipeline = socket.pipeline();
|
||||
//添加解析器
|
||||
//日志解析器
|
||||
pipeline.addLast(new LoggingHandler(LogLevel.INFO));
|
||||
//Http解析器
|
||||
pipeline.addLast(new HttpServerCodec());
|
||||
//块解析器
|
||||
pipeline.addLast(new ChunkedWriteHandler());
|
||||
//聚合解析器
|
||||
pipeline.addLast(new HttpObjectAggregator(16384));
|
||||
//设置uri为/connect
|
||||
pipeline.addLast(new WebSocketServerProtocolHandler("/chat"));
|
||||
//自定义解析器
|
||||
pipeline.addLast(chatFrameHandler);
|
||||
}
|
||||
}
|
32
lib-chat/src/main/java/cn/wzpmc/ChatStart.java
Normal file
32
lib-chat/src/main/java/cn/wzpmc/ChatStart.java
Normal file
@ -0,0 +1,32 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@MapperScan("cn.wzpmc.dao")
|
||||
@SpringBootApplication
|
||||
public class ChatStart {
|
||||
private static Netty netty;
|
||||
@Autowired
|
||||
public void setNetty(Netty netty){
|
||||
ChatStart.netty = netty;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void main(String[] args) {
|
||||
SpringApplication springApplication = new SpringApplication(ChatStart.class);
|
||||
ConfigurableApplicationContext run = springApplication.run(args);
|
||||
ChatFrameHandler.setCommandHandler(run);
|
||||
springApplication.addListeners(netty);
|
||||
netty.start();
|
||||
}
|
||||
}
|
15
lib-chat/src/main/java/cn/wzpmc/DataSourceFactory.java
Normal file
15
lib-chat/src/main/java/cn/wzpmc/DataSourceFactory.java
Normal file
@ -0,0 +1,15 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
public class DataSourceFactory extends PooledDataSourceFactory {
|
||||
public DataSourceFactory(){
|
||||
this.dataSource = new DruidDataSource();
|
||||
}
|
||||
}
|
77
lib-chat/src/main/java/cn/wzpmc/Netty.java
Normal file
77
lib-chat/src/main/java/cn/wzpmc/Netty.java
Normal file
@ -0,0 +1,77 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* @version 1.0
|
||||
* Created On 2022/5/14
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class Netty implements ApplicationListener<ContextClosedEvent> {
|
||||
@Value("${server.port}")
|
||||
private int port;
|
||||
private final EventLoopGroup boss = new NioEventLoopGroup();
|
||||
private final EventLoopGroup work = new NioEventLoopGroup();
|
||||
private Channel channel;
|
||||
private final ChatHandler chatHandler;
|
||||
@Autowired
|
||||
public Netty(ChatHandler chatHandler){
|
||||
this.chatHandler = chatHandler;
|
||||
}
|
||||
/**
|
||||
* Start netty service
|
||||
*/
|
||||
public void start(){
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
bootstrap.group(boss,work)
|
||||
//设置日志处理器
|
||||
.handler(new LoggingHandler(LogLevel.DEBUG))
|
||||
//设置自主处理器
|
||||
.childHandler(chatHandler)
|
||||
//设置通道
|
||||
.channel(NioServerSocketChannel.class);
|
||||
try {
|
||||
ChannelFuture future = bootstrap.bind(new InetSocketAddress(port)).sync();
|
||||
if (future.isSuccess()){
|
||||
log.info("Chat Server started on 0.0.0.0:{}",port);
|
||||
}
|
||||
this.channel = future.channel();
|
||||
future.channel().closeFuture().sync();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void destroy() {
|
||||
log.info("Shutdown Netty Server...");
|
||||
if(channel != null) {
|
||||
channel.close();
|
||||
}
|
||||
work.shutdownGracefully();
|
||||
boss.shutdownGracefully();
|
||||
log.info("Shutdown Netty Server Success!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
this.destroy();
|
||||
}
|
||||
}
|
52
lib-chat/src/main/java/cn/wzpmc/dao/ChatDao.java
Normal file
52
lib-chat/src/main/java/cn/wzpmc/dao/ChatDao.java
Normal file
@ -0,0 +1,52 @@
|
||||
package cn.wzpmc.dao;
|
||||
|
||||
import cn.wzpmc.pojo.Message;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
*/
|
||||
@Mapper
|
||||
@Repository
|
||||
public interface ChatDao {
|
||||
/**
|
||||
* send a message to database
|
||||
* @param message the message you want to send
|
||||
*/
|
||||
void sendMessage(Message message);
|
||||
|
||||
/**
|
||||
* get message with id > id_min and id < id_max
|
||||
*
|
||||
* @param count the count of message
|
||||
* @param idMin the max value of id
|
||||
* @return some message objects
|
||||
*/
|
||||
ArrayList<Message> getMessage(@Param("id_min") int idMin, @Param("count") int count);
|
||||
|
||||
/**
|
||||
* get all messages count
|
||||
* @return count of message
|
||||
*/
|
||||
Integer getCount();
|
||||
|
||||
/**
|
||||
* get a user's head portrait with username
|
||||
* @param username username
|
||||
* @return a base64 of user's head portrait
|
||||
*/
|
||||
String getUserHeadPortrait(@Param("username") String username);
|
||||
|
||||
/**
|
||||
* recall a message
|
||||
* @param id the id of the message you want to recall
|
||||
*/
|
||||
void recall(@Param("id") Integer id);
|
||||
|
||||
List<Message> getNewMessage(@Param("id_min") Integer minId,@Param("id_max") Integer maxId,@Param("count") Integer count);
|
||||
}
|
14
lib-chat/src/main/java/cn/wzpmc/pojo/HeadPortrait.java
Normal file
14
lib-chat/src/main/java/cn/wzpmc/pojo/HeadPortrait.java
Normal file
@ -0,0 +1,14 @@
|
||||
package cn.wzpmc.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class HeadPortrait {
|
||||
private String username;
|
||||
private String base64;
|
||||
}
|
64
lib-chat/src/main/java/cn/wzpmc/pojo/Message.java
Normal file
64
lib-chat/src/main/java/cn/wzpmc/pojo/Message.java
Normal file
@ -0,0 +1,64 @@
|
||||
package cn.wzpmc.pojo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import top.xinsin.enums.MessageTypes;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Message {
|
||||
private int id;
|
||||
private String content;
|
||||
private String sender;
|
||||
private int recall;
|
||||
private String sendtime;
|
||||
private String base64;
|
||||
private MessageTypes type;
|
||||
public Message(int id){
|
||||
this.id = id;
|
||||
}
|
||||
public Message(int id, String content, String sender, int recall, String sendtime, String type, String base64){
|
||||
this.content = content;
|
||||
this.sender = sender;
|
||||
this.id = id;
|
||||
this.recall = recall;
|
||||
this.type = MessageTypes.valueOf(type);
|
||||
this.sendtime = sendtime;
|
||||
this.base64 = base64;
|
||||
}
|
||||
public Message(String content, String sender,String type){
|
||||
this.content = content;
|
||||
this.sender = sender;
|
||||
this.type = MessageTypes.valueOf(type);
|
||||
Calendar calendar= Calendar.getInstance();
|
||||
SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd :hh:mm:ss");
|
||||
this.sendtime = dateFormat.format(calendar.getTime());
|
||||
}
|
||||
public Message(String content, String sender,String type,String sendtime){
|
||||
this.content = content;
|
||||
this.sender = sender;
|
||||
this.type = MessageTypes.valueOf(type);
|
||||
this.sendtime = sendtime;
|
||||
}
|
||||
public Message(int id,String content,String sender,int recall,String type,String sendtime){
|
||||
this.content = content;
|
||||
this.sender = sender;
|
||||
this.id = id;
|
||||
this.recall = recall;
|
||||
this.type = MessageTypes.valueOf(type);
|
||||
this.sendtime = sendtime;
|
||||
}
|
||||
}
|
||||
|
121
lib-chat/src/main/java/cn/wzpmc/services/ChatCommandHandler.java
Normal file
121
lib-chat/src/main/java/cn/wzpmc/services/ChatCommandHandler.java
Normal file
@ -0,0 +1,121 @@
|
||||
package cn.wzpmc.services;
|
||||
|
||||
import cn.wzpmc.dao.ChatDao;
|
||||
import cn.wzpmc.pojo.Message;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelId;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.xinsin.interfaces.NettyCommandHandler;
|
||||
import top.xinsin.utils.JwtTokenUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ChatCommandHandler implements NettyCommandHandler {
|
||||
private final ChatDao chatDao;
|
||||
private final Map<ChannelId, Channel> users = new ConcurrentHashMap<>();
|
||||
private final Map<ChannelId, Boolean> loginTable = new ConcurrentHashMap<>();
|
||||
@Autowired
|
||||
public ChatCommandHandler(ChatDao chatDao){
|
||||
this.chatDao = chatDao;
|
||||
}
|
||||
public JSONObject handlerLogin(ChannelHandlerContext channelHandlerContext, String token){
|
||||
Boolean right = JwtTokenUtils.isRight(token);
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
loginTable.put(id, right);
|
||||
JSONObject result = new JSONObject();
|
||||
result.fluentPut("success", right);
|
||||
return result;
|
||||
}
|
||||
public List<Message> handlerGet(ChannelHandlerContext channelHandlerContext,Integer minId,Integer count){
|
||||
if (!loginTable.getOrDefault(channelHandlerContext.channel().id(), false)) {
|
||||
return null;
|
||||
}
|
||||
return chatDao.getMessage(minId, count);
|
||||
}
|
||||
public List<Message> handlerGetNew(ChannelHandlerContext channelHandlerContext,Integer minId,Integer maxId,Integer count){
|
||||
if (!loginTable.getOrDefault(channelHandlerContext.channel().id(), false)) {
|
||||
return null;
|
||||
}
|
||||
return chatDao.getNewMessage(minId, maxId, count);
|
||||
}
|
||||
public int handlerCount(ChannelHandlerContext channelHandlerContext){
|
||||
if (!loginTable.getOrDefault(channelHandlerContext.channel().id(), false)) {
|
||||
return -1;
|
||||
}
|
||||
return chatDao.getCount();
|
||||
}
|
||||
public JSONObject handlerSend(ChannelHandlerContext channelHandlerContext, String content,String sender,Integer type){
|
||||
if (!loginTable.getOrDefault(channelHandlerContext.channel().id(), false)) {
|
||||
return null;
|
||||
}
|
||||
String type_ = "img";
|
||||
if (type == 0){
|
||||
type_ = "text";
|
||||
}
|
||||
Message message = new Message(content, sender, type_);
|
||||
chatDao.sendMessage(message);
|
||||
String base64 = chatDao.getUserHeadPortrait(sender);
|
||||
message.setBase64(base64);
|
||||
ChannelId id = channelHandlerContext.channel().id();
|
||||
JSONObject toAll = new JSONObject().fluentPut("op", "add").fluentPut("data", new JSONObject().fluentPut("message", message));
|
||||
for (Map.Entry<ChannelId, Channel> channelIdChannelEntry : users.entrySet()) {
|
||||
if (!channelIdChannelEntry.getKey().equals(id)) {
|
||||
channelIdChannelEntry.getValue().writeAndFlush(new TextWebSocketFrame(toAll.toJSONString()));
|
||||
}
|
||||
}
|
||||
|
||||
return new JSONObject().fluentPut("message", message);
|
||||
}
|
||||
public void handlerRemove(ChannelHandlerContext channelHandlerContext, Integer id){
|
||||
if (!loginTable.getOrDefault(channelHandlerContext.channel().id(), false)) {
|
||||
return;
|
||||
}
|
||||
JSONObject toAll = new JSONObject().fluentPut("op", "recall").fluentPut("data", new JSONObject().fluentPut("id", id));
|
||||
for (Map.Entry<ChannelId, Channel> channelIdChannelEntry : users.entrySet()) {
|
||||
if (!channelIdChannelEntry.getKey().equals(channelHandlerContext.channel().id())) {
|
||||
channelIdChannelEntry.getValue().writeAndFlush(new TextWebSocketFrame(toAll.toJSONString()));
|
||||
}
|
||||
}
|
||||
chatDao.recall(id);
|
||||
}
|
||||
public void handlerPing(ChannelHandlerContext channelHandlerContext){
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.fluentPut("op", "pong").fluentPut("data",new JSONObject().fluentPut("time", System.currentTimeMillis()));
|
||||
channel.writeAndFlush(new TextWebSocketFrame(jsonObject.toJSONString()));
|
||||
}
|
||||
@Override
|
||||
public void handlerClose(ChannelHandlerContext channelHandlerContext) {
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
users.remove(id);
|
||||
log.info("User {} disconnected in channel {}",channel.remoteAddress(), id.asShortText());
|
||||
}
|
||||
@Override
|
||||
public void handlerJoin(ChannelHandlerContext channelHandlerContext) {
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
users.put(id, channel);
|
||||
log.info("User {} connected in channel {}",channel.remoteAddress(), id.asShortText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerError(ChannelHandlerContext channelHandlerContext, Throwable cause) {
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
users.remove(id);
|
||||
log.info("User {} disconnected with error in channel {}",channel.remoteAddress(), id.asShortText());
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
29
lib-chat/src/main/resources/application.yml
Normal file
29
lib-chat/src/main/resources/application.yml
Normal file
@ -0,0 +1,29 @@
|
||||
server:
|
||||
port: 8005
|
||||
spring:
|
||||
datasource:
|
||||
username: witstalk
|
||||
password: witsTalk
|
||||
url: jdbc:mysql://wzpmc.cn:3306/witstalk?serverTimezone=UTC-8
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
# druid配置
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
initialSize: 5
|
||||
minIdle: 5
|
||||
maxActive: 20
|
||||
maxWait: 60000
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
poolPreparedStatements: true
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
|
||||
filters: stat,wall,log4j
|
||||
maxPoolPreparedStatementPerConnectionSize: 20
|
||||
useGlobalDataSourceStat: true
|
||||
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
|
||||
mybatis:
|
||||
mapper-locations: classpath:cn/wzpmc/dao/*Dao.xml
|
||||
type-aliases-package: cn.wzpmc.dao
|
30
lib-chat/src/main/resources/cn/wzpmc/dao/ChatDao.xml
Normal file
30
lib-chat/src/main/resources/cn/wzpmc/dao/ChatDao.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.wzpmc.dao.ChatDao">
|
||||
<insert id="sendMessage" parameterType="cn.wzpmc.pojo.Message" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into message
|
||||
set content=#{content},
|
||||
sender=#{sender},
|
||||
type=#{type},
|
||||
sendtime=#{sendtime};
|
||||
</insert>
|
||||
<update id="recall" parameterType="cn.wzpmc.pojo.Message">
|
||||
update message
|
||||
set recall=1
|
||||
where id = #{id};
|
||||
</update>
|
||||
<select id="getMessage" resultType="cn.wzpmc.pojo.Message">
|
||||
select m.*,u.base64 from message m inner join user u on u.username = m.sender where m.id >= #{id_min} and m.recall = 0 order by m.id desc limit #{count};
|
||||
</select>
|
||||
<select id="getUserHeadPortrait" resultType="java.lang.String">
|
||||
select `base64` from user where BINARY `username`=#{username};
|
||||
</select>
|
||||
<select id="getCount" resultType="java.lang.Integer">
|
||||
select COUNT(*) from message;
|
||||
</select>
|
||||
<select id="getNewMessage" resultType="cn.wzpmc.pojo.Message">
|
||||
select m.*,u.base64 from message m inner join user u on u.username = m.sender where m.id >= #{id_min} and m.id <= #{id_max} and m.recall = 0 order by m.id desc limit #{count};
|
||||
</select>
|
||||
</mapper>
|
55
lib-fileTransfer/pom.xml
Normal file
55
lib-fileTransfer/pom.xml
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>witsTalk</artifactId>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lib-fileTransfer</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<artifactId>lib-utils</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!--spring-boot mybatis依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--druid连接池依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.2.9</version>
|
||||
</dependency>
|
||||
|
||||
<!--mysqlJDBC依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!--<directory>..\target</directory>-->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<!--suppress MavenModelInspection -->
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
package top.xinsin;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/14 14:00
|
||||
* @version 1.0
|
||||
*/
|
||||
@MapperScan("top.xinsin.dao")
|
||||
@SpringBootApplication
|
||||
public class FileTransferStart {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FileTransferStart.class,args);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package top.xinsin.config;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/11 21:59
|
||||
* @version 1.0
|
||||
* mvn配置
|
||||
*/
|
||||
|
||||
@SpringBootConfiguration
|
||||
public class GlobalWebMvcConfig implements WebMvcConfigurer {
|
||||
/**
|
||||
* 解决跨域问题
|
||||
*/
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
//添加映射路径
|
||||
registry.addMapping("/**")
|
||||
//是否发送Cookie
|
||||
.allowCredentials(true)
|
||||
//设置放行哪些原始域 SpringBoot2.4.4下低版本使用.allowedOrigins("*")
|
||||
.allowedOriginPatterns("*")
|
||||
//放行哪些请求方式
|
||||
.allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS", "HEAD")
|
||||
//.allowedMethods("*") //或者放行全部
|
||||
//放行哪些原始请求头部信息
|
||||
.allowedHeaders("*")
|
||||
//暴露哪些原始请求头部信息
|
||||
.exposedHeaders("*");
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package top.xinsin.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import top.xinsin.interceptor.AuthenticationInterceptor;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/21 22:14
|
||||
* @version 1.0
|
||||
*/
|
||||
@Configuration
|
||||
public class InterceptorConfig implements WebMvcConfigurer {
|
||||
private AuthenticationInterceptor authenticationInterceptor;
|
||||
@Autowired
|
||||
public InterceptorConfig(AuthenticationInterceptor authenticationInterceptor){
|
||||
this.authenticationInterceptor = authenticationInterceptor;
|
||||
}
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(authenticationInterceptor)
|
||||
//拦截
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns("/file/api/downloadFile")
|
||||
.excludePathPatterns("/api/fileUpload");
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package top.xinsin.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.xinsin.service.FileDownloadService;
|
||||
import top.xinsin.service.FileService;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/22 11:20
|
||||
* @version 1.0
|
||||
*/
|
||||
@RestController
|
||||
public class FileController {
|
||||
private final FileService fileService;
|
||||
@Autowired
|
||||
public FileController(FileService fileService){
|
||||
this.fileService = fileService;
|
||||
}
|
||||
@GetMapping("/file/fileDelete")
|
||||
public RData<String> fileDelete(@RequestParam("id")Integer id,@RequestParam("md5")String md5){
|
||||
return fileService.fileDelete(id,md5);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package top.xinsin.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.xinsin.pojo.FileObject;
|
||||
import top.xinsin.service.FileDownloadService;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/2 15:09
|
||||
* @version 1.0
|
||||
*/
|
||||
@RestController
|
||||
public class FileDownloadController {
|
||||
private final FileDownloadService fileDownloadService;
|
||||
@Autowired
|
||||
public FileDownloadController(FileDownloadService fileDownloadService){
|
||||
this.fileDownloadService = fileDownloadService;
|
||||
}
|
||||
@GetMapping("/file/api/getName")
|
||||
public RData<String> getFileName(@RequestParam("md5") String md5){
|
||||
return fileDownloadService.getFileName(new FileObject(md5));
|
||||
}
|
||||
|
||||
@GetMapping("/file/api/downloadFile")
|
||||
public ResponseEntity<InputStreamResource> getFile(@RequestParam("md5") String md5, @RequestParam("filename") String filename, @RequestParam("token") String token) throws IOException {
|
||||
return fileDownloadService.getFile(md5, filename, token);
|
||||
}
|
||||
|
||||
@PostMapping("/file/api/getAllFileNames")
|
||||
public RData<JSONObject> getAllFileNames(@RequestParam("min_id") int minId, @RequestParam("pageSize") Integer pageSize) {
|
||||
return fileDownloadService.getAllFileNames(minId,pageSize);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package top.xinsin.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.xinsin.service.FileUpLoadService;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/14 14:07
|
||||
* @version 1.0
|
||||
*/
|
||||
@RestController
|
||||
public class FileUpLoadController {
|
||||
private final FileUpLoadService fileUpLoadService;
|
||||
|
||||
@Autowired
|
||||
public FileUpLoadController(FileUpLoadService fileUpLoadService) {
|
||||
this.fileUpLoadService = fileUpLoadService;
|
||||
}
|
||||
|
||||
@PostMapping("/file/api/fileUpload")
|
||||
public RData<String> fileUpload(@RequestBody MultipartFile file, HttpServletRequest request) throws NoSuchAlgorithmException, IOException {
|
||||
return fileUpLoadService.fileUpload(file, request);
|
||||
}
|
||||
|
||||
@GetMapping("/file/api/debug")
|
||||
public String debug() {
|
||||
return "123";
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package top.xinsin.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.xinsin.pojo.FileObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/23 19:07
|
||||
* @version 1.0
|
||||
*/
|
||||
@Repository
|
||||
public interface FileDownloadMapper {
|
||||
/**
|
||||
* 获取原始文件名称
|
||||
* @param fileObject 文件对象
|
||||
* @return 文件名称
|
||||
*/
|
||||
String getFileName(FileObject fileObject);
|
||||
|
||||
/**
|
||||
* 获取所有文件的名称
|
||||
*
|
||||
* @return 文件名称列表
|
||||
*/
|
||||
ArrayList<FileObject> getAllFileNames(@Param("min_id")Integer minId,@Param("pageSize")Integer pageSize);
|
||||
|
||||
Integer selectFileCount();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package top.xinsin.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import top.xinsin.pojo.FileObject;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/22 11:23
|
||||
* @version 1.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface FileMapper {
|
||||
Integer deleteByIdAndMd5(Integer id, String md5);
|
||||
FileObject selectByMD5(String md5);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package top.xinsin.dao;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.xinsin.pojo.FileObject;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/2 15:11
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Repository
|
||||
public interface FileUploadMapper {
|
||||
/**
|
||||
* 上传文件
|
||||
* @param fileObject 文件对象
|
||||
*/
|
||||
void addFile(FileObject fileObject);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package top.xinsin.dao;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.xinsin.pojo.AuthVerificationTokenJwt;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/22 9:22
|
||||
* @version 1.0
|
||||
*/
|
||||
@Repository
|
||||
public interface UserVerifyMapper {
|
||||
/**
|
||||
* 用户验证映射
|
||||
* @param authVerificationTokenJwt 用户的JWTToken
|
||||
* @return 用户是否在线
|
||||
*/
|
||||
Integer userVerify(AuthVerificationTokenJwt authVerificationTokenJwt);
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package top.xinsin.interceptor;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import sun.misc.BASE64Decoder;
|
||||
import top.xinsin.pojo.AuthVerificationTokenJwt;
|
||||
import top.xinsin.service.UserVerifyService;
|
||||
import top.xinsin.utils.JwtTokenUtils;
|
||||
import top.xinsin.utils.ResponseData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/21 22:16
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AuthenticationInterceptor implements HandlerInterceptor {
|
||||
@Autowired
|
||||
private UserVerifyService userVerifyService;
|
||||
public static final String OPTIONS = "OPTIONS";
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
if (OPTIONS.equals(request.getMethod())) {
|
||||
return true;
|
||||
}
|
||||
// 从http请求头中取出token
|
||||
final String token = request.getHeader("Access-Token");
|
||||
//解决跨域问题
|
||||
response.setHeader("Access-Control-Allow-Origin","*");
|
||||
response.setHeader("Access-Control-Allow-Headers","*");
|
||||
ResponseData responseData;
|
||||
String data = null;
|
||||
System.out.println(token);
|
||||
//获取token
|
||||
DecodedJWT tokenInfo = JwtTokenUtils.getTokenInfo(token);
|
||||
try {
|
||||
//解析token
|
||||
data = new String(new BASE64Decoder().decodeBuffer(tokenInfo.getPayload()), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//查找json字符串中的结尾 并取下标将其分割
|
||||
assert data != null;
|
||||
data = data.substring(0,data.indexOf("}",39) + 1);
|
||||
//获取实体类对象
|
||||
AuthVerificationTokenJwt authVerificationTokenJwt = JSONObject.parseObject(data, AuthVerificationTokenJwt.class);
|
||||
if (!userVerifyService.userVerify(authVerificationTokenJwt)) {
|
||||
log.warn("AuthenticationInterceptor --> username --> " + authVerificationTokenJwt.getUsername() + ": TokenVerifyFail:(");
|
||||
responseData = new ResponseData("token验证失败,该用户可能还没有登陆", HttpStatus.UNAUTHORIZED);
|
||||
}else{
|
||||
log.info("AuthenticationInterceptor --> username --> " + authVerificationTokenJwt.getUsername() + ": TokenVerifySuccess:)");
|
||||
return true;
|
||||
}
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.getWriter().write(responseData.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package top.xinsin.pojo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/21 22:09
|
||||
* @version 1.0
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AuthVerificationTokenJwt {
|
||||
private String id;
|
||||
private String exp;
|
||||
private String username;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package top.xinsin.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/24 14:48
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class FileObject {
|
||||
private int id;
|
||||
private long size;
|
||||
private String name;
|
||||
private String md5;
|
||||
private String uploadTime;
|
||||
private String uploaderName;
|
||||
private int uploaderId;
|
||||
|
||||
public FileObject(String name, long size, String md5, int uploadId) {
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.md5 = md5;
|
||||
this.uploaderId = uploadId;
|
||||
}
|
||||
|
||||
public FileObject(String md5) {
|
||||
this.md5 = md5;
|
||||
}
|
||||
|
||||
public FileObject(int id, long size, String name, String md5, String uploadTime, String uploaderName) {
|
||||
this.id = id;
|
||||
this.size = size;
|
||||
this.name = name;
|
||||
this.md5 = md5;
|
||||
this.uploadTime = uploadTime;
|
||||
this.uploaderName = uploaderName;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package top.xinsin.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.xinsin.dao.FileDownloadMapper;
|
||||
import top.xinsin.pojo.FileObject;
|
||||
import top.xinsin.utils.JwtTokenUtils;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/2 15:14
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FileDownloadService {
|
||||
|
||||
private final FileDownloadMapper fileDownloadMapper;
|
||||
/**
|
||||
* 文件保存目录
|
||||
*/
|
||||
@Value("${saveFolder}")
|
||||
private String fileSaveFolder;
|
||||
@Autowired
|
||||
public FileDownloadService(FileDownloadMapper fileDownloadMapper) {
|
||||
this.fileDownloadMapper = fileDownloadMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始文件名
|
||||
* @param fileObject 文件对象
|
||||
* @return 原始文件名
|
||||
*/
|
||||
public RData<String> getFileName(FileObject fileObject){
|
||||
log.info("getFileName,args:{}",fileObject);
|
||||
String fileName = fileDownloadMapper.getFileName(fileObject);
|
||||
return RData.success(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有文件名称
|
||||
*
|
||||
* @return 文件名称
|
||||
*/
|
||||
public RData<JSONObject> getAllFileNames(Integer minId, Integer pageSize) {
|
||||
log.info("getAllFileNames --> begin");
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.fluentPut("files", fileDownloadMapper.getAllFileNames(minId,pageSize));
|
||||
jsonObject.fluentPut("total", fileDownloadMapper.selectFileCount());
|
||||
return RData.success(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
* @param md5 文件md5值
|
||||
* @param filename 下载时的文件名
|
||||
* @param token JWTToken
|
||||
* @return 文件
|
||||
* @throws IOException 当文件获取失败时抛出
|
||||
*/
|
||||
public ResponseEntity<InputStreamResource> getFile(String md5, String filename,String token) throws IOException {
|
||||
//验证token合法性
|
||||
JwtTokenUtils.verify(token);
|
||||
log.info("getFile,md5={},filename={}",md5,filename);
|
||||
FileSystemResource file = new FileSystemResource(fileSaveFolder + File.separator + md5);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", filename));
|
||||
headers.add("Pragma", "no-cache");
|
||||
headers.add("Expires", "0");
|
||||
|
||||
return ResponseEntity.ok().headers(headers)
|
||||
.contentLength(file.contentLength())
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
.body(new InputStreamResource(file.getInputStream()));
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package top.xinsin.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.xinsin.dao.FileMapper;
|
||||
import top.xinsin.dao.FileUploadMapper;
|
||||
import top.xinsin.enums.HttpCodes;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/22 11:22
|
||||
* @version 1.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FileService {
|
||||
private final FileMapper fileMapper;
|
||||
/**
|
||||
* 文件保存的目录
|
||||
*/
|
||||
@Value("${saveFolder}")
|
||||
private String fileSaveFolder;
|
||||
@Autowired
|
||||
public FileService(FileMapper fileMapper) {
|
||||
this.fileMapper = fileMapper;
|
||||
}
|
||||
|
||||
public RData<String> fileDelete(Integer id, String md5) {
|
||||
Integer count = fileMapper.deleteByIdAndMd5(id,md5);
|
||||
if (count != 0){
|
||||
log.info("数据库数据删除成功-#:{},md5:{}",id,md5);
|
||||
log.info("即将删除本地文件");
|
||||
File file = new File(fileSaveFolder, md5);
|
||||
if (file.delete()) {
|
||||
log.info("本地文件删除成功-md5:{}",md5);
|
||||
return RData.success("删除成功");
|
||||
}
|
||||
}
|
||||
return RData.failed(HttpCodes.HTTP_CODES500,"删除文件失败");
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package top.xinsin.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.xinsin.dao.FileMapper;
|
||||
import top.xinsin.dao.FileUploadMapper;
|
||||
import top.xinsin.enums.HttpCodes;
|
||||
import top.xinsin.pojo.FileObject;
|
||||
import top.xinsin.utils.FileUtils;
|
||||
import top.xinsin.utils.JwtTokenUtils;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/18 13:40
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FileUpLoadService {
|
||||
|
||||
private final FileUploadMapper fileUploadMapper;
|
||||
private final FileMapper fileMapper;
|
||||
|
||||
/**
|
||||
* 文件保存的目录
|
||||
*/
|
||||
@Value("${saveFolder}")
|
||||
private String fileSaveFolder;
|
||||
@Autowired
|
||||
public FileUpLoadService(FileUploadMapper fileUploadMapper,FileMapper fileMapper) {
|
||||
this.fileUploadMapper = fileUploadMapper;
|
||||
this.fileMapper = fileMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件服务
|
||||
*
|
||||
* @param file 文件
|
||||
* @param request 请求
|
||||
* @return 是否成功
|
||||
*/
|
||||
|
||||
public RData<String> fileUpload(MultipartFile file, HttpServletRequest request) throws NoSuchAlgorithmException, IOException {
|
||||
if (file.isEmpty()) {
|
||||
return RData.failed(HttpCodes.HTTP_CODES401, "文件是空的");
|
||||
}
|
||||
log.info("starting saving");
|
||||
//获取原始文件名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
//获取文件的InputStream
|
||||
InputStream input = file.getInputStream();
|
||||
//拼接文件保存路径
|
||||
String savePath = fileSaveFolder + File.separator + originalFilename;
|
||||
//获取文件对象
|
||||
File file1 = new File(savePath);
|
||||
//获取磁盘中的文件的OutputStream
|
||||
FileOutputStream out = new FileOutputStream(file1);
|
||||
//使用IOUtils来复制
|
||||
IOUtils.copy(input,out);
|
||||
//计算磁盘中文件的md5
|
||||
String md5 = FileUtils.calcMd5(file1);
|
||||
// 去重
|
||||
FileObject fileObject1 = fileMapper.selectByMD5(md5);
|
||||
if (fileObject1 != null){
|
||||
return RData.failed(HttpCodes.HTTP_CODES500,"请不要上传相同的文件");
|
||||
}
|
||||
log.info("fileSaved,SavedName:{},md5:{}",savePath,md5);
|
||||
//关闭输入流
|
||||
input.close();
|
||||
//关闭输出流
|
||||
out.close();
|
||||
//清除缓存
|
||||
System.gc();
|
||||
log.info("closeIOStream");
|
||||
log.info("fileRename to {}",md5);
|
||||
//获取使用md5拼接的文件名
|
||||
String newSavePath = fileSaveFolder + File.separator + md5;
|
||||
File newFile = new File(newSavePath);
|
||||
if(newFile.exists()){
|
||||
log.info("fileExists!");
|
||||
}else{
|
||||
//将磁盘中的文件重命名
|
||||
boolean b = file1.renameTo(newFile);
|
||||
log.info("fileRenamed,Succeed:{}",b);
|
||||
log.info("Sending to database");
|
||||
int id = Integer.parseInt(JwtTokenUtils.getTokenInfo(request.getHeader("Access-Token")).getClaim("id").asString());
|
||||
//新建FileObject
|
||||
FileObject fileObject = new FileObject(originalFilename, file.getSize(), md5, id);
|
||||
//上传数据库
|
||||
fileUploadMapper.addFile(fileObject);
|
||||
log.info("Sanded");
|
||||
log.info("fileUpload done");
|
||||
}
|
||||
return RData.success(md5);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package top.xinsin.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.xinsin.dao.UserVerifyMapper;
|
||||
import top.xinsin.pojo.AuthVerificationTokenJwt;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/22 9:21
|
||||
* @version 1.0
|
||||
*/
|
||||
@Service
|
||||
public class UserVerifyService {
|
||||
private final UserVerifyMapper userVerifyMapper;
|
||||
@Autowired
|
||||
public UserVerifyService(UserVerifyMapper userVerifyMapper) {
|
||||
this.userVerifyMapper = userVerifyMapper;
|
||||
}
|
||||
|
||||
public boolean userVerify(AuthVerificationTokenJwt authVerificationTokenJwt){
|
||||
return userVerifyMapper.userVerify(authVerificationTokenJwt) == 1;
|
||||
}
|
||||
}
|
36
lib-fileTransfer/src/main/resources/application.yml
Normal file
36
lib-fileTransfer/src/main/resources/application.yml
Normal file
@ -0,0 +1,36 @@
|
||||
server:
|
||||
port: 8004
|
||||
spring:
|
||||
datasource:
|
||||
username: witstalk
|
||||
password: witsTalk
|
||||
url: jdbc:mysql://wzpmc.cn:3306/witstalk?serverTimezone=UTC-8
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
# druid配置
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
initialSize: 5
|
||||
minIdle: 5
|
||||
maxActive: 20
|
||||
maxWait: 60000
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
poolPreparedStatements: true
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
|
||||
filters: stat,wall,log4j
|
||||
maxPoolPreparedStatementPerConnectionSize: 20
|
||||
useGlobalDataSourceStat: true
|
||||
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
|
||||
mvc:
|
||||
static-path-pattern: /static/**
|
||||
mybatis:
|
||||
mapper-locations: classpath:top/xinsin/dao/*Mapping.xml
|
||||
type-aliases-package: top.xinsin.dao
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 20GB
|
||||
max-request-size: 20GB
|
||||
saveFolder: ./filesave
|
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.xinsin.dao.FileDownloadMapper">
|
||||
<select id="getFileName" parameterType="top.xinsin.pojo.FileObject" resultType="java.lang.String">
|
||||
select name
|
||||
from file
|
||||
where md5 = #{md5};
|
||||
</select>
|
||||
<select id="getAllFileNames" resultType="top.xinsin.pojo.FileObject">
|
||||
select f.id, f.size, f.`name`, f.md5, f.uploadTime, u.username as uploaderName
|
||||
from file f
|
||||
INNER JOIN `user` u on u.id = f.uploaderId
|
||||
LIMIT #{min_id} ,#{pageSize}
|
||||
</select>
|
||||
<select id="selectFileCount" resultType="java.lang.Integer">
|
||||
select count(*)
|
||||
from file;
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="top.xinsin.dao.FileMapper">
|
||||
|
||||
<delete id="deleteByIdAndMd5">
|
||||
delete
|
||||
from file
|
||||
where id = #{id} and md5 = #{md5};
|
||||
</delete>
|
||||
<select id="selectByMD5" resultType="top.xinsin.pojo.FileObject">
|
||||
select *
|
||||
from file where md5 = #{md5};
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.xinsin.dao.FileUploadMapper">
|
||||
<insert id="addFile" parameterType="top.xinsin.pojo.FileObject">
|
||||
insert into file
|
||||
set size=#{size},
|
||||
name=#{name},
|
||||
md5=#{md5},
|
||||
uploadTime=now(),
|
||||
uploaderId=#{uploaderId};
|
||||
</insert>
|
||||
</mapper>
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.xinsin.dao.UserVerifyMapper">
|
||||
<select id="userVerify" resultType="java.lang.Integer" parameterType="top.xinsin.pojo.AuthVerificationTokenJwt">
|
||||
select `online` from `user` where BINARY username = #{username} and id = #{id}
|
||||
</select>
|
||||
</mapper>
|
60
lib-user/pom.xml
Normal file
60
lib-user/pom.xml
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>witsTalk</artifactId>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lib-user</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<artifactId>lib-utils</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-httpclient</groupId>
|
||||
<artifactId>commons-httpclient</artifactId>
|
||||
<version>3.1</version>
|
||||
</dependency>
|
||||
<!--spring-boot mybatis依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--druid连接池依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.2.9</version>
|
||||
</dependency>
|
||||
|
||||
<!--mysqlJDBC依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<!--<directory>..\target</directory>-->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<!--suppress MavenModelInspection -->
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
17
lib-user/src/main/java/top/xinsin/UserStart.java
Normal file
17
lib-user/src/main/java/top/xinsin/UserStart.java
Normal file
@ -0,0 +1,17 @@
|
||||
package top.xinsin;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/11 17:16
|
||||
* @version 1.0
|
||||
*/
|
||||
@MapperScan("top.xinsin.dao")
|
||||
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class })
|
||||
public class UserStart {
|
||||
public static void main(String[] args){SpringApplication.run(UserStart.class,args);}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package top.xinsin.config;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/11 21:59
|
||||
* @version 1.0
|
||||
* mvn配置
|
||||
*/
|
||||
|
||||
@SpringBootConfiguration
|
||||
public class GlobalWebMvcConfig implements WebMvcConfigurer {
|
||||
/**
|
||||
* 解决跨域问题
|
||||
*/
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
//添加映射路径
|
||||
registry.addMapping("/**")
|
||||
//是否发送Cookie
|
||||
.allowCredentials(true)
|
||||
//设置放行哪些原始域 SpringBoot2.4.4下低版本使用.allowedOrigins("*")
|
||||
.allowedOriginPatterns("*")
|
||||
//放行哪些请求方式
|
||||
.allowedMethods("GET", "POST", "DELETE", "PUT", "HEAD")
|
||||
//.allowedMethods("*") //或者放行全部
|
||||
//放行哪些原始请求头部信息
|
||||
.allowedHeaders("*")
|
||||
//暴露哪些原始请求头部信息
|
||||
.exposedHeaders("*");
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package top.xinsin.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import top.xinsin.interceptor.AuthenticationInterceptor;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/12 21:05
|
||||
* @version 1.0
|
||||
*/
|
||||
@Configuration
|
||||
public class InterceptorConfig implements WebMvcConfigurer {
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new AuthenticationInterceptor()).
|
||||
//拦截
|
||||
addPathPatterns("/**").
|
||||
//放行登录接口
|
||||
excludePathPatterns("/user/api/login").
|
||||
//放行验证码接口
|
||||
excludePathPatterns("/user/api/vc").
|
||||
//放行注册接口
|
||||
excludePathPatterns("/user/api/adduser").
|
||||
// 放行token验证登陆接口
|
||||
excludePathPatterns("/user/api/autoLogin").
|
||||
//放行调试接口
|
||||
excludePathPatterns("/user/api/debug");
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package top.xinsin.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.xinsin.pojo.User;
|
||||
import top.xinsin.services.UserService;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/12 10:49
|
||||
* @version 1.0
|
||||
*/
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class CheckController {
|
||||
|
||||
private final UserService userService;
|
||||
@Autowired
|
||||
public CheckController(UserService userService){
|
||||
this.userService = userService;
|
||||
}
|
||||
public static HashMap<User, Date> checklist = new HashMap<>();
|
||||
@PostMapping("/user/api/check")
|
||||
public RData<Date> check(@RequestBody User user){
|
||||
log.info("Check args:user=" + user);
|
||||
checklist.put(user,new Date());
|
||||
userService.setOnline(user);
|
||||
return RData.success(checklist.get(user));
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package top.xinsin.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.xinsin.pojo.Route;
|
||||
import top.xinsin.pojo.Vo.RouteVO;
|
||||
import top.xinsin.services.RouteService;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/24 16:05
|
||||
* @version 1.0
|
||||
*/
|
||||
@RestController
|
||||
public class RouteController {
|
||||
private final RouteService routeService;
|
||||
|
||||
@Autowired
|
||||
public RouteController(RouteService routeService) {
|
||||
this.routeService = routeService;
|
||||
}
|
||||
@GetMapping("/user/sys/getRoutes")
|
||||
public RData<JSONObject> getRoutes(@RequestParam("page")Integer page, @RequestParam("pageNum")Integer pageNum){return routeService.getRoutes(page,pageNum);}
|
||||
@PostMapping("/user/sys/addRoute")
|
||||
public RData<String> addRoute(@RequestBody Route route){return routeService.addRoute(route);}
|
||||
@GetMapping("/user/sys/updateStatus")
|
||||
public RData<String> updateStatus(@RequestParam("id")Integer id,@RequestParam("status")Integer status){return routeService.updateStatus(id,status);}
|
||||
@PostMapping("/user/sys/updateRoute")
|
||||
public RData<String> updateRoute(@RequestBody Route route){return routeService.updateRoute(route);}
|
||||
@GetMapping("/user/api/getRouter")
|
||||
public RData<List<RouteVO>> getRouter(@RequestParam("auth")String auth){return routeService.getRouter(auth);}
|
||||
}
|
146
lib-user/src/main/java/top/xinsin/controller/UserController.java
Normal file
146
lib-user/src/main/java/top/xinsin/controller/UserController.java
Normal file
@ -0,0 +1,146 @@
|
||||
package top.xinsin.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.xinsin.pojo.User;
|
||||
import top.xinsin.services.UserService;
|
||||
import top.xinsin.utils.IpUtils;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/11 18:06
|
||||
* @version 1.0
|
||||
*/
|
||||
@RestController
|
||||
public class UserController {
|
||||
private final UserService userService;
|
||||
@Autowired
|
||||
public UserController(UserService userService){
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录接口
|
||||
* @param user 用户
|
||||
* @param response 请求体
|
||||
* @return 是否可以登陆
|
||||
*/
|
||||
@PostMapping("/user/api/login")
|
||||
public RData<JSONObject> login(@RequestBody User user, HttpServletResponse response) {
|
||||
return userService.canLogin(user,response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加用户接口
|
||||
* @param user 需要添加的用户
|
||||
* @return 受影响行数
|
||||
*/
|
||||
@PostMapping("/user/api/adduser")
|
||||
public RData<JSONObject> addUser(@RequestBody User user) {return userService.addUser(user);}
|
||||
|
||||
/**
|
||||
* @param user 需要修改密码的用户,此用户的password字段为需要为修改后的密码
|
||||
* @return 受影响行数
|
||||
*/
|
||||
@PostMapping("/user/api/changepassword")
|
||||
public RData<JSONObject> changePassword(@RequestBody User user, HttpServletRequest request) {
|
||||
return userService.changePassword(user, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户头像接口
|
||||
*
|
||||
* @param user 需要修改头像的用户,此用户的head
|
||||
* @return 受影响行数
|
||||
*/
|
||||
@PostMapping("/user/api/setHeadPortrait")
|
||||
public RData<JSONObject> setHeadPortrait(@RequestBody User user, HttpServletRequest request) {
|
||||
return userService.setHeadPortrait(user, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户头像接口
|
||||
* @param username 用户名
|
||||
* @return 用户头像的base64
|
||||
*/
|
||||
@GetMapping("/user/api/getUserHeadPortrait/{username}")
|
||||
public String getUserHeadPortrait(@PathVariable String username){
|
||||
return userService.getUserHeadPortrait(username).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有在线用户接口
|
||||
*
|
||||
* @return 在线用户
|
||||
*/
|
||||
@GetMapping("/user/api/getOnlineUser")
|
||||
public RData<List<User>> getOnlineUser() {
|
||||
return userService.getOnlineUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户名
|
||||
*
|
||||
* @param user 新用户
|
||||
* @param request 请求
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PostMapping("/user/api/changeUsername")
|
||||
public RData<Boolean> changeUsername(@RequestBody User user, HttpServletRequest request, HttpServletResponse response) {
|
||||
return userService.changeUsername(user, request, response);
|
||||
}
|
||||
@GetMapping("/user/api/setUserExclusiveColor")
|
||||
public RData<Boolean> setUserExclusiveColor(@RequestHeader("color") String color,@RequestHeader("username")String username){return userService.setColorById(color,username);}
|
||||
@GetMapping("/user/api/autoLogin")
|
||||
public RData<JSONObject> autoLogin(HttpServletRequest request){return userService.autoLogin(request);}
|
||||
@Value("${map-key}")
|
||||
private String key;
|
||||
@SneakyThrows
|
||||
@GetMapping("/user/api/getWeather")
|
||||
public RData<JSONObject> getWeather(HttpServletRequest httpServletRequest){
|
||||
String ipAddr = IpUtils.getIpAddr(httpServletRequest);
|
||||
// 检测为本地ip则进行默认地点查询
|
||||
if ("127.0.0.1".equals(ipAddr)){
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(15000);
|
||||
GetMethod getMethod = new GetMethod("https://restapi.amap.com/v3/ip?key=" + key);
|
||||
httpClient.executeMethod(getMethod);
|
||||
String responseBodyAsString = getMethod.getResponseBodyAsString();
|
||||
JSONObject jsonObject = JSON.parseObject(responseBodyAsString);
|
||||
getMethod.releaseConnection();
|
||||
GetMethod getWeather = new GetMethod("https://restapi.amap.com/v3/weather/weatherInfo?key=" + key + "&city="+jsonObject.getString("adcode")+"&awextensions=base");
|
||||
httpClient.executeMethod(getWeather);
|
||||
String getWeatherResult = getWeather.getResponseBodyAsString();
|
||||
getWeather.releaseConnection();
|
||||
return RData.success(JSON.parseObject(getWeatherResult));
|
||||
}else{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(15000);
|
||||
GetMethod getMethod = new GetMethod("https://restapi.amap.com/v3/ip?key=" + key + "&ip=" + ipAddr);
|
||||
httpClient.executeMethod(getMethod);
|
||||
String result = getMethod.getResponseBodyAsString();
|
||||
getMethod.releaseConnection();
|
||||
String adcode = JSON.parseObject(result).getString("adcode");
|
||||
if (adcode != null){
|
||||
GetMethod getWeather = new GetMethod("https://restapi.amap.com/v3/weather/weatherInfo?key=" + key + "&city=" + adcode + "&extensions=base");
|
||||
httpClient.executeMethod(getWeather);
|
||||
String getWeatherResult = getWeather.getResponseBodyAsString();
|
||||
getWeather.releaseConnection();
|
||||
return RData.success(JSON.parseObject(getWeatherResult));
|
||||
}else{
|
||||
return RData.success(new JSONObject().fluentPut("status","未查询到相关天气信息"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
lib-user/src/main/java/top/xinsin/dao/RouteMapper.java
Normal file
27
lib-user/src/main/java/top/xinsin/dao/RouteMapper.java
Normal file
@ -0,0 +1,27 @@
|
||||
package top.xinsin.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import top.xinsin.pojo.Route;
|
||||
import top.xinsin.pojo.Vo.RouteVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/24 16:05
|
||||
* @version 1.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface RouteMapper {
|
||||
List<Route> selectRoute(Integer page, Integer pageNum);
|
||||
|
||||
Integer selectCount();
|
||||
|
||||
Integer insert(Route route);
|
||||
|
||||
Integer updateStatusById(Integer id, Integer status);
|
||||
|
||||
Integer updateRouteById(Route route);
|
||||
|
||||
List<RouteVO> SelectRouteByAuth(String auth);
|
||||
}
|
78
lib-user/src/main/java/top/xinsin/dao/UserMapper.java
Normal file
78
lib-user/src/main/java/top/xinsin/dao/UserMapper.java
Normal file
@ -0,0 +1,78 @@
|
||||
package top.xinsin.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.xinsin.pojo.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@Repository
|
||||
public interface UserMapper {
|
||||
/**
|
||||
* Check can user login
|
||||
* @param user user need to log in
|
||||
* @return if can ,return this user else return null
|
||||
*/
|
||||
User canLogin(User user);
|
||||
|
||||
/**
|
||||
* add a new user to db
|
||||
* @param user user need to add
|
||||
* @return 影响行数
|
||||
*/
|
||||
int addUser(User user);
|
||||
|
||||
/**
|
||||
* changeUser's password
|
||||
* @param user user with new password
|
||||
* @return 影响行数
|
||||
*/
|
||||
int changePassword(User user);
|
||||
|
||||
/**
|
||||
* set a user's status to online
|
||||
* @param user user need to online
|
||||
* @return 影响行数
|
||||
*/
|
||||
int setOnline(User user);
|
||||
|
||||
/**
|
||||
* set a user's status to offline
|
||||
* @param user user need to offline
|
||||
* @return 影响行数
|
||||
*/
|
||||
int setOffline(User user);
|
||||
|
||||
/**
|
||||
* set a user's headingImg
|
||||
*
|
||||
* @param user user with new base64
|
||||
*/
|
||||
void setHeadPortrait(User user);
|
||||
|
||||
/**
|
||||
* get users online equals 1
|
||||
* @return all online equals 1 user
|
||||
*/
|
||||
ArrayList<User> getOnlineUser();
|
||||
|
||||
/**
|
||||
* get a user's headingImg
|
||||
*
|
||||
* @param username the name of this user
|
||||
* @return base64
|
||||
*/
|
||||
String getUserHeadPortrait(@Param("username") String username);
|
||||
|
||||
void changeUsername(String username, String old_username);
|
||||
|
||||
void changeUsernameUpdateMessage(String username, String old_username);
|
||||
|
||||
void setColorById(String exclusiveColor,String username);
|
||||
User selectALLBYIdAndUsername(String username,Integer id);
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package top.xinsin.interceptor;
|
||||
|
||||
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
|
||||
import com.auth0.jwt.exceptions.SignatureVerificationException;
|
||||
import com.auth0.jwt.exceptions.TokenExpiredException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import top.xinsin.utils.JwtTokenUtils;
|
||||
import top.xinsin.utils.ResponseData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/12 19:17
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class AuthenticationInterceptor implements HandlerInterceptor {
|
||||
public static final String OPTIONS = "OPTIONS";
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
|
||||
if (OPTIONS.equals(request.getMethod())) {
|
||||
return true;
|
||||
}
|
||||
// 从http请求头中取出token
|
||||
final String token = request.getHeader("Access-Token");
|
||||
//解决跨域问题
|
||||
response.setHeader("Access-Control-Allow-Origin","*");
|
||||
//解决跨域问题
|
||||
response.setHeader("Access-Control-Allow-Headers","*");
|
||||
ResponseData responseData;
|
||||
try {
|
||||
JwtTokenUtils.verify(token);
|
||||
return true;
|
||||
} catch (SignatureVerificationException e) {
|
||||
log.info("用户验证了无效签名");
|
||||
responseData = new ResponseData("无效签名", HttpStatus.UNAUTHORIZED);
|
||||
}catch (TokenExpiredException e){
|
||||
log.info("用户验证的签名已过期");
|
||||
responseData = new ResponseData("签名已过期", HttpStatus.UNAUTHORIZED);
|
||||
}catch (AlgorithmMismatchException e){
|
||||
log.info("用户验证的token算法不一致");
|
||||
responseData = new ResponseData("token算法不一致", HttpStatus.UNAUTHORIZED);
|
||||
}catch (Exception e){
|
||||
log.info("token无效或者是空的");
|
||||
responseData = new ResponseData("token无效", HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.getWriter().write(responseData.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
18
lib-user/src/main/java/top/xinsin/pojo/Online.java
Normal file
18
lib-user/src/main/java/top/xinsin/pojo/Online.java
Normal file
@ -0,0 +1,18 @@
|
||||
package top.xinsin.pojo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import top.xinsin.enums.Auth;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2022/1/16 21:46
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Online {
|
||||
private String username;
|
||||
private Auth auth;
|
||||
private String headPortrait;
|
||||
}
|
25
lib-user/src/main/java/top/xinsin/pojo/Route.java
Normal file
25
lib-user/src/main/java/top/xinsin/pojo/Route.java
Normal file
@ -0,0 +1,25 @@
|
||||
package top.xinsin.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/24 16:03
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class Route {
|
||||
private Integer id;
|
||||
private String path;
|
||||
private String name;
|
||||
private String parentId;
|
||||
private String component;
|
||||
private String title;
|
||||
private String auth;
|
||||
private Integer status;
|
||||
private String remark;
|
||||
private String createId;
|
||||
private String createTime;
|
||||
private String updateId;
|
||||
private String updateTime;
|
||||
}
|
39
lib-user/src/main/java/top/xinsin/pojo/User.java
Normal file
39
lib-user/src/main/java/top/xinsin/pojo/User.java
Normal file
@ -0,0 +1,39 @@
|
||||
package top.xinsin.pojo;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import top.xinsin.enums.Auth;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/11 20:09
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
public class User {
|
||||
private int id;
|
||||
private String username;
|
||||
private String password;
|
||||
private Auth auth = Auth.user;
|
||||
private int online;
|
||||
private String lastLogin;
|
||||
private String exclusiveColor;
|
||||
private String base64;
|
||||
public User(String username){
|
||||
this.username = username;
|
||||
}
|
||||
public User(String username,String password){
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
public User(String username,String password,String auth){
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.auth = Auth.valueOf(auth);
|
||||
}
|
||||
}
|
18
lib-user/src/main/java/top/xinsin/pojo/Vo/RouteVO.java
Normal file
18
lib-user/src/main/java/top/xinsin/pojo/Vo/RouteVO.java
Normal file
@ -0,0 +1,18 @@
|
||||
package top.xinsin.pojo.Vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/24 16:26
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class RouteVO {
|
||||
private Integer id;
|
||||
private String path;
|
||||
private String name;
|
||||
private String parentId;
|
||||
private String component;
|
||||
private String title;
|
||||
}
|
52
lib-user/src/main/java/top/xinsin/services/RouteService.java
Normal file
52
lib-user/src/main/java/top/xinsin/services/RouteService.java
Normal file
@ -0,0 +1,52 @@
|
||||
package top.xinsin.services;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.xinsin.dao.RouteMapper;
|
||||
import top.xinsin.pojo.Route;
|
||||
import top.xinsin.pojo.Vo.RouteVO;
|
||||
import top.xinsin.utils.RData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/24 16:05
|
||||
* @version 1.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class RouteService {
|
||||
private final RouteMapper routeMapper;
|
||||
@Autowired
|
||||
public RouteService(RouteMapper routeMapper) {
|
||||
this.routeMapper = routeMapper;
|
||||
}
|
||||
public RData<JSONObject> getRoutes(Integer page, Integer pageNum) {
|
||||
List<Route> routes = routeMapper.selectRoute(page,pageNum);
|
||||
Integer count = routeMapper.selectCount();
|
||||
return null;
|
||||
}
|
||||
|
||||
public RData<String> addRoute(Route route) {
|
||||
Integer num = routeMapper.insert(route);
|
||||
return null;
|
||||
}
|
||||
|
||||
public RData<String> updateStatus(Integer id, Integer status) {
|
||||
Integer num = routeMapper.updateStatusById(id,status);
|
||||
return null;
|
||||
}
|
||||
|
||||
public RData<String> updateRoute(Route route) {
|
||||
Integer num = routeMapper.updateRouteById(route);
|
||||
return null;
|
||||
}
|
||||
|
||||
public RData<List<RouteVO>> getRouter(String auth) {
|
||||
List<RouteVO> routeVOS = routeMapper.SelectRouteByAuth(auth);
|
||||
return null;
|
||||
}
|
||||
}
|
154
lib-user/src/main/java/top/xinsin/services/UserService.java
Normal file
154
lib-user/src/main/java/top/xinsin/services/UserService.java
Normal file
@ -0,0 +1,154 @@
|
||||
package top.xinsin.services;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.xinsin.dao.UserMapper;
|
||||
import top.xinsin.enums.HttpCodes;
|
||||
import top.xinsin.pojo.User;
|
||||
import top.xinsin.utils.JwtTokenUtils;
|
||||
import top.xinsin.utils.RData;
|
||||
import top.xinsin.utils.SqlUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/11 21:21
|
||||
* @version 1.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UserService {
|
||||
private final UserMapper userMapper;
|
||||
@Autowired
|
||||
public UserService(UserMapper userMapper){
|
||||
this.userMapper = userMapper;
|
||||
}
|
||||
public RData<JSONObject> canLogin(User user, HttpServletResponse response){
|
||||
log.info("canLogin args:user=" + user);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
String password = user.getPassword();
|
||||
String sha512Hex = DigestUtils.sha512Hex(password);
|
||||
user.setPassword(sha512Hex);
|
||||
User user1 = userMapper.canLogin(user);
|
||||
if (user1 != null){
|
||||
Map<String,String> payload = new HashMap<>(10);
|
||||
payload.put("id",String.valueOf(user1.getId()));
|
||||
payload.put("username",user1.getUsername());
|
||||
String token = JwtTokenUtils.getToken(payload);
|
||||
response.setHeader("token", token);
|
||||
response.setHeader("Access-Control-Expose-Headers", "token");
|
||||
jsonObject.fluentPut("canLogin", true)
|
||||
.fluentPut("base64", user1.getBase64())
|
||||
.fluentPut("auth",user1.getAuth().toString())
|
||||
.fluentPut("exclusiveColor",user1.getExclusiveColor())
|
||||
.fluentPut("username",user1.getUsername())
|
||||
.fluentPut("id",user1.getId());
|
||||
} else {
|
||||
jsonObject.fluentPut("canLogin", false);
|
||||
return RData.failed(HttpCodes.HTTP_CODES501, jsonObject);
|
||||
}
|
||||
return RData.success(jsonObject);
|
||||
}
|
||||
|
||||
public RData<JSONObject> addUser(User user) {
|
||||
log.info("addUser args:user=" + user);
|
||||
user.setPassword(DigestUtils.sha512Hex(user.getPassword()));
|
||||
JSONObject jsonObject = SqlUtils.insertOperate(userMapper.addUser(user));
|
||||
return RData.success(jsonObject);
|
||||
}
|
||||
|
||||
public RData<JSONObject> changePassword(User user, HttpServletRequest request) {
|
||||
String token = request.getHeader("Access-Token");
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.fluentPut("is_success", false);
|
||||
if (JwtTokenUtils.isUser(token, user.getUsername())) {
|
||||
String s = DigestUtils.sha512Hex(user.getPassword());
|
||||
user.setPassword(s);
|
||||
jsonObject = SqlUtils.updateOperate(userMapper.changePassword(user));
|
||||
jsonObject.fluentPut("is_success", true);
|
||||
return RData.success(jsonObject);
|
||||
}
|
||||
return RData.failed(HttpCodes.INVALID_TOKEN, jsonObject);
|
||||
}
|
||||
|
||||
public void setOnline(User user) {
|
||||
SqlUtils.updateOperate(userMapper.setOnline(user));
|
||||
user.setOnline(1);
|
||||
}
|
||||
|
||||
public void setOffline(User user) {
|
||||
SqlUtils.updateOperate(userMapper.setOffline(user));
|
||||
user.setOnline(0);
|
||||
}
|
||||
|
||||
public RData<JSONObject> setHeadPortrait(User user, HttpServletRequest request) {
|
||||
// 因为传入两个string所以password即为base64
|
||||
String token = request.getHeader("Access-Token");
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
if (JwtTokenUtils.isUser(token, user.getUsername())) {
|
||||
userMapper.setHeadPortrait(user);
|
||||
jsonObject.fluentPut("is_success", true);
|
||||
return RData.success(jsonObject);
|
||||
}else{
|
||||
jsonObject.fluentPut("is_success", false);
|
||||
return RData.failed(HttpCodes.INVALID_TOKEN, jsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
public RData<String> getUserHeadPortrait(String name) {
|
||||
String b64 = userMapper.getUserHeadPortrait(name);
|
||||
return RData.success(b64);
|
||||
}
|
||||
|
||||
public RData<List<User>> getOnlineUser() {
|
||||
return RData.success(userMapper.getOnlineUser());
|
||||
}
|
||||
|
||||
public RData<Boolean> changeUsername(User user, HttpServletRequest request, HttpServletResponse httpServletResponse) {
|
||||
String token = request.getHeader("Access-Token");
|
||||
DecodedJWT tokenInfo = JwtTokenUtils.getTokenInfo(token);
|
||||
String username = tokenInfo.getClaim("username").asString();
|
||||
String id = tokenInfo.getClaim("id").asString();
|
||||
String newUsername = user.getUsername();
|
||||
userMapper.changeUsername(newUsername, username);
|
||||
userMapper.changeUsernameUpdateMessage(newUsername, username);
|
||||
Map<String, String> payload = new HashMap<>();
|
||||
payload.put("id", id);
|
||||
payload.put("username", newUsername);
|
||||
httpServletResponse.addHeader("token", JwtTokenUtils.getToken(payload));
|
||||
return RData.success(true);
|
||||
}
|
||||
public RData<Boolean> setColorById(String exclusiveColor,String username){
|
||||
userMapper.setColorById(exclusiveColor,username);
|
||||
return RData.success(true);
|
||||
}
|
||||
|
||||
public RData<JSONObject> autoLogin(HttpServletRequest request) {
|
||||
String token = request.getHeader("Access-Token");
|
||||
DecodedJWT tokenInfo = JwtTokenUtils.getTokenInfo(token);
|
||||
String username = tokenInfo.getClaim("username").asString();
|
||||
String id = tokenInfo.getClaim("id").asString();
|
||||
User user = userMapper.selectALLBYIdAndUsername(username, Integer.parseInt(id));
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
if (user != null){
|
||||
jsonObject.fluentPut("status", true)
|
||||
.fluentPut("base64", user.getBase64())
|
||||
.fluentPut("auth",user.getAuth().toString())
|
||||
.fluentPut("exclusiveColor",user.getExclusiveColor())
|
||||
.fluentPut("username",user.getUsername())
|
||||
.fluentPut("id",user.getId());
|
||||
}else{
|
||||
jsonObject.fluentPut("status",false);
|
||||
}
|
||||
return RData.success(jsonObject);
|
||||
}
|
||||
}
|
43
lib-user/src/main/java/top/xinsin/tasks/CheckTask.java
Normal file
43
lib-user/src/main/java/top/xinsin/tasks/CheckTask.java
Normal file
@ -0,0 +1,43 @@
|
||||
package top.xinsin.tasks;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import top.xinsin.pojo.User;
|
||||
import top.xinsin.services.UserService;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static top.xinsin.controller.CheckController.checklist;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/12 11:03
|
||||
* @version 1.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
@Slf4j
|
||||
public class CheckTask {
|
||||
private final UserService userService;
|
||||
@Autowired
|
||||
public CheckTask(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate=1000)
|
||||
public void checkTasks(){
|
||||
Date now = new Date();
|
||||
for (User user : checklist.keySet()) {
|
||||
Date time = checklist.get(user);
|
||||
if(time.getTime() + 1000*60*60*2 <= now.getTime()){
|
||||
userService.setOffline(user);
|
||||
checklist.remove(user);
|
||||
log.info("CheckList remove user=" + user);
|
||||
}
|
||||
log.info("CheckTask user=" + user);
|
||||
}
|
||||
}
|
||||
}
|
34
lib-user/src/main/resources/application.yml
Normal file
34
lib-user/src/main/resources/application.yml
Normal file
@ -0,0 +1,34 @@
|
||||
server:
|
||||
port: 8003
|
||||
spring:
|
||||
datasource:
|
||||
username: witstalk
|
||||
password: witsTalk
|
||||
url: jdbc:mysql://wzpmc.cn:3306/witstalk?serverTimezone=UTC-8
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
# druid配置
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
initialSize: 5
|
||||
minIdle: 5
|
||||
maxActive: 20
|
||||
maxWait: 60000
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
poolPreparedStatements: true
|
||||
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
|
||||
filters: stat,wall,log4j
|
||||
maxPoolPreparedStatementPerConnectionSize: 20
|
||||
useGlobalDataSourceStat: true
|
||||
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
|
||||
mvc:
|
||||
static-path-pattern: /static/**
|
||||
mybatis:
|
||||
mapper-locations: classpath:top/xinsin/dao/*Mapping.xml
|
||||
type-aliases-package: top.xinsin.dao
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
map-key: 3d665cbd98ac252863b898625450e2a3
|
28
lib-user/src/main/resources/top/xinsin/dao/RouteMapper.xml
Normal file
28
lib-user/src/main/resources/top/xinsin/dao/RouteMapper.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="top.xinsin.dao.RouteMapper">
|
||||
<insert id="insert">
|
||||
insert into route (path, name, parentId, component, title, auth, remark, createId, createTime)
|
||||
values (#{path},#{name},#{parentId},#{component},#{title},#{auth},#{remark},#{createId},now());
|
||||
</insert>
|
||||
<update id="updateStatusById">
|
||||
update route
|
||||
set status = #{status}
|
||||
where id = #{id};
|
||||
</update>
|
||||
<update id="updateRouteById">
|
||||
update route
|
||||
set path = #{path},name=#{name},parentId=#{parentId},component=#{component},title=#{title},auth=#{auth},remark=#{remark},
|
||||
updateId=#{updateId},updateTime=now()
|
||||
where id=#{id}
|
||||
</update>
|
||||
<select id="selectRoute" resultType="top.xinsin.pojo.Route">
|
||||
select * from route r limit #{page},#{pageNum};
|
||||
</select>
|
||||
<select id="selectCount" resultType="java.lang.Integer">
|
||||
select count(*) from route;
|
||||
</select>
|
||||
<select id="SelectRouteByAuth" resultType="top.xinsin.pojo.Vo.RouteVO">
|
||||
select r.id,r.name,r.parentId,r.path,r.component,r.title from route r where auth = #{auth};
|
||||
</select>
|
||||
</mapper>
|
64
lib-user/src/main/resources/top/xinsin/dao/UserMapper.xml
Normal file
64
lib-user/src/main/resources/top/xinsin/dao/UserMapper.xml
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="top.xinsin.dao.UserMapper">
|
||||
<insert id="addUser" parameterType="top.xinsin.pojo.User">
|
||||
insert into user set username = #{username}, password = #{password}, auth = #{auth},base64= #{base64};
|
||||
</insert>
|
||||
|
||||
<update id="changePassword" parameterType="top.xinsin.pojo.User">
|
||||
update user set password = #{password} where BINARY username = #{username};
|
||||
</update>
|
||||
|
||||
<update id="setOnline" parameterType="top.xinsin.pojo.User">
|
||||
update user set online = 1 where BINARY username = #{username} and password=#{password};
|
||||
</update>
|
||||
|
||||
<update id="setOffline" parameterType="top.xinsin.pojo.User">
|
||||
update user
|
||||
set online = 0
|
||||
where BINARY username = #{username}
|
||||
and password = #{password};
|
||||
</update>
|
||||
|
||||
<select id="canLogin" parameterType="top.xinsin.pojo.User" resultType="top.xinsin.pojo.User">
|
||||
select *
|
||||
from user
|
||||
where BINARY username = #{username}
|
||||
and password = #{password}
|
||||
and ban = 0;
|
||||
</select>
|
||||
<update id="setHeadPortrait" parameterType="top.xinsin.pojo.User">
|
||||
update user
|
||||
set base64 = #{password}
|
||||
where BINARY username = #{username};
|
||||
</update>
|
||||
<update id="changeUsername" parameterType="top.xinsin.pojo.User">
|
||||
update user
|
||||
set username = #{username}
|
||||
where BINARY username = #{old_username};
|
||||
</update>
|
||||
<update id="changeUsernameUpdateMessage">
|
||||
update message
|
||||
set sender = #{username}
|
||||
where BINARY sender = #{old_username};
|
||||
</update>
|
||||
<select id="getUserHeadPortrait" resultType="java.lang.String">
|
||||
select `base64`
|
||||
from user
|
||||
where BINARY `username` = #{username};
|
||||
</select>
|
||||
<select id="getOnlineUser" resultType="top.xinsin.pojo.User">
|
||||
SELECT last_login
|
||||
from user
|
||||
WHERE `online` = 1;
|
||||
</select>
|
||||
<select id="selectALLBYIdAndUsername" resultType="top.xinsin.pojo.User">
|
||||
select id, username, auth, base64, exclusiveColor
|
||||
from user where username = #{username} and id = #{id} and ban = 0;
|
||||
</select>
|
||||
<update id="setColorById">
|
||||
update user
|
||||
set exclusiveColor = #{exclusiveColor}
|
||||
where BINARY username = #{username};
|
||||
</update>
|
||||
</mapper>
|
18
lib-user/src/test/java/top/xinsin/TestIp.java
Normal file
18
lib-user/src/test/java/top/xinsin/TestIp.java
Normal file
@ -0,0 +1,18 @@
|
||||
package top.xinsin;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/5 13:39
|
||||
* @version 1.0
|
||||
*/
|
||||
public class TestIp {
|
||||
@Test
|
||||
public void testIp01() throws UnknownHostException {
|
||||
System.out.println(InetAddress.getLocalHost().getHostAddress());
|
||||
}
|
||||
}
|
15
lib-user/src/test/java/top/xinsin/TestVerify.java
Normal file
15
lib-user/src/test/java/top/xinsin/TestVerify.java
Normal file
@ -0,0 +1,15 @@
|
||||
package top.xinsin;
|
||||
|
||||
import org.apache.commons.codec.cli.Digest;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TestVerify {
|
||||
@Test
|
||||
public void test(){
|
||||
String username = "DongYifeng";
|
||||
String username1 = "DongYiFeng";
|
||||
System.out.println(DigestUtils.sha512Hex(DigestUtils.md5Hex(username)).equals(DigestUtils.sha512Hex(DigestUtils.md5Hex(username1))));
|
||||
System.out.println(DigestUtils.sha512Hex(DigestUtils.md5Hex("13630594060cloua")));
|
||||
}
|
||||
}
|
31
lib-utils/pom.xml
Normal file
31
lib-utils/pom.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>witsTalk</artifactId>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lib-utils</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!--spring-boot web模块-->
|
||||
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec-http</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
17
lib-utils/src/main/java/top/xinsin/enums/Auth.java
Normal file
17
lib-utils/src/main/java/top/xinsin/enums/Auth.java
Normal file
@ -0,0 +1,17 @@
|
||||
package top.xinsin.enums;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/11 20:33
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum Auth {
|
||||
/**
|
||||
* 管理员
|
||||
*/
|
||||
admin,
|
||||
/**
|
||||
* 普通用户
|
||||
*/
|
||||
user
|
||||
}
|
57
lib-utils/src/main/java/top/xinsin/enums/HttpCodes.java
Normal file
57
lib-utils/src/main/java/top/xinsin/enums/HttpCodes.java
Normal file
@ -0,0 +1,57 @@
|
||||
package top.xinsin.enums;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public enum HttpCodes {
|
||||
/**
|
||||
* 200
|
||||
* 成功执行
|
||||
*/
|
||||
HTTP_CODES200(200,"接口一不小心执行成功啦!"),
|
||||
/**
|
||||
* 500
|
||||
* 服务器错误
|
||||
*/
|
||||
|
||||
HTTP_CODES500(500,"哎呀,错误了请节哀!"),
|
||||
/**
|
||||
* 401
|
||||
* 数据错误
|
||||
*/
|
||||
HTTP_CODES401(401,"你这请求是坏的,你不会写吗?"),
|
||||
/**
|
||||
* 501
|
||||
* 账号密码错误
|
||||
*/
|
||||
HTTP_CODES501(501,"帐号或密码错误!"),
|
||||
/**
|
||||
* 250
|
||||
* token验证错误
|
||||
*/
|
||||
INVALID_TOKEN(250,"令牌验证错误"),
|
||||
/**
|
||||
* 251
|
||||
* 无权限访问
|
||||
*/
|
||||
ACCESS_DENIED( 251,"你没有权限访问");
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
|
||||
HttpCodes(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
16
lib-utils/src/main/java/top/xinsin/enums/MessageTypes.java
Normal file
16
lib-utils/src/main/java/top/xinsin/enums/MessageTypes.java
Normal file
@ -0,0 +1,16 @@
|
||||
package top.xinsin.enums;
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/11 20:33
|
||||
* @version 1.0
|
||||
*/
|
||||
public enum MessageTypes {
|
||||
/**
|
||||
* 文本消息
|
||||
*/
|
||||
text,
|
||||
/**
|
||||
* 图片消息
|
||||
*/
|
||||
img
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package top.xinsin.interfaces;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
public interface NettyCommandHandler {
|
||||
void handlerClose(ChannelHandlerContext channelHandlerContext);
|
||||
void handlerJoin(ChannelHandlerContext channelHandlerContext);
|
||||
default void handlerError(ChannelHandlerContext channelHandlerContext, Throwable cause){
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
42
lib-utils/src/main/java/top/xinsin/utils/FileUtils.java
Normal file
42
lib-utils/src/main/java/top/xinsin/utils/FileUtils.java
Normal file
@ -0,0 +1,42 @@
|
||||
package top.xinsin.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/1/2 11:32
|
||||
* @version 1.0
|
||||
*/
|
||||
public class FileUtils {
|
||||
private static final char[] HEX_CODE = "0123456789ABCDEF".toCharArray();
|
||||
/**
|
||||
* 计算文件 MD5
|
||||
* @return 返回文件的md5字符串,如果计算过程中任务的状态变为取消或暂停,返回null, 如果有其他异常,返回空字符串
|
||||
*/
|
||||
public static String calcMd5(File file) throws IOException, NoSuchAlgorithmException {
|
||||
try (InputStream stream = Files.newInputStream(file.toPath(), StandardOpenOption.READ)) {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
byte[] buf = new byte[8192];
|
||||
int len;
|
||||
while ((len = stream.read(buf)) > 0) {
|
||||
digest.update(buf, 0, len);
|
||||
}
|
||||
return toHexString(digest.digest());
|
||||
}
|
||||
}
|
||||
|
||||
public static String toHexString(byte[] data) {
|
||||
StringBuilder r = new StringBuilder(data.length * 2);
|
||||
for (byte b : data) {
|
||||
r.append(HEX_CODE[(b >> 4) & 0xF]);
|
||||
r.append(HEX_CODE[(b & 0xF)]);
|
||||
}
|
||||
return r.toString();
|
||||
}
|
||||
}
|
49
lib-utils/src/main/java/top/xinsin/utils/IpUtils.java
Normal file
49
lib-utils/src/main/java/top/xinsin/utils/IpUtils.java
Normal file
@ -0,0 +1,49 @@
|
||||
package top.xinsin.utils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* Created On 2022/12/5 13:37
|
||||
* @version 1.0
|
||||
*/
|
||||
public class IpUtils {
|
||||
public static String getIpAddr(HttpServletRequest request) {
|
||||
String ipAddress = null;
|
||||
try {
|
||||
ipAddress = request.getHeader("X-Forwarded-For");
|
||||
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||
ipAddress = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||
ipAddress = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||
ipAddress = request.getRemoteAddr();
|
||||
if (ipAddress.equals("127.0.0.1")) {
|
||||
// 根据网卡取本机配置的IP
|
||||
try {
|
||||
ipAddress = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
|
||||
if (ipAddress != null) {
|
||||
if (ipAddress.contains(",")) {
|
||||
return ipAddress.split(",")[0];
|
||||
} else {
|
||||
return ipAddress;
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
80
lib-utils/src/main/java/top/xinsin/utils/JwtTokenUtils.java
Normal file
80
lib-utils/src/main/java/top/xinsin/utils/JwtTokenUtils.java
Normal file
@ -0,0 +1,80 @@
|
||||
package top.xinsin.utils;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTCreator;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author xinxin
|
||||
* Created On 2021/12/12 20:42
|
||||
* @version 1.0
|
||||
*/
|
||||
public class JwtTokenUtils {
|
||||
private static final String KEY = "G%k7H4lK;D1@L87Kio8j^ns56lJ68";
|
||||
|
||||
/**
|
||||
* 创建token
|
||||
* @param map 字段
|
||||
* @return token
|
||||
*/
|
||||
public static String getToken(Map<String,String> map){
|
||||
Calendar instance = Calendar.getInstance();
|
||||
//默认两个小时过期
|
||||
instance.add(Calendar.HOUR,2);
|
||||
//创建jwt builder
|
||||
JWTCreator.Builder builder = JWT.create();
|
||||
//payload
|
||||
map.forEach(builder::withClaim);
|
||||
//指定令牌过期时间
|
||||
return builder.withExpiresAt(instance.getTime())
|
||||
.sign(Algorithm.HMAC512(KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证token是否合法
|
||||
* @param token token
|
||||
*/
|
||||
public static void verify(String token){
|
||||
JWT.require(Algorithm.HMAC512(KEY)).build().verify(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证token是否合法
|
||||
* @param token token
|
||||
* @return 是否为合法token
|
||||
*/
|
||||
public static Boolean isRight(String token){
|
||||
try{
|
||||
verify(token);
|
||||
return true;
|
||||
}catch (Exception e){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从token中提取信息
|
||||
*
|
||||
* @param token token
|
||||
* @return token中包含的信息
|
||||
*/
|
||||
public static DecodedJWT getTokenInfo(String token) {
|
||||
return JWT.require(Algorithm.HMAC512(KEY)).build().verify(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断token与用户名是否对应
|
||||
*
|
||||
* @param token token
|
||||
* @param username 用户名
|
||||
* @return 是否对应
|
||||
*/
|
||||
public static boolean isUser(String token, String username) {
|
||||
String tokenUsername = getTokenInfo(token).getClaim("username").asString();
|
||||
return tokenUsername.equals(username);
|
||||
}
|
||||
}
|
108
lib-utils/src/main/java/top/xinsin/utils/NettyUtils.java
Normal file
108
lib-utils/src/main/java/top/xinsin/utils/NettyUtils.java
Normal file
@ -0,0 +1,108 @@
|
||||
package top.xinsin.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.xinsin.interfaces.NettyCommandHandler;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@Component
|
||||
@NoArgsConstructor
|
||||
public class NettyUtils<T extends NettyCommandHandler> {
|
||||
public static void handler(Class<? extends NettyCommandHandler> handler, NettyCommandHandler commandHandler,ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) {
|
||||
String text = textWebSocketFrame.text();
|
||||
JSONObject jsonObject = JSON.parseObject(text);
|
||||
String command = jsonObject.getString("op");
|
||||
char c = command.charAt(0);
|
||||
char c1 = Character.toUpperCase(c);
|
||||
String s = command.replaceFirst(String.valueOf(c), String.valueOf(c1));
|
||||
jsonObject.remove("op");
|
||||
List<Class<?>> types = new ArrayList<>();
|
||||
List<Object> args = new ArrayList<>();
|
||||
types.add(ChannelHandlerContext.class);
|
||||
args.add(channelHandlerContext);
|
||||
AtomicBoolean hasNull = new AtomicBoolean(false);
|
||||
for (Map.Entry<String, Object> stringObjectEntry : jsonObject.entrySet()) {
|
||||
Object value = stringObjectEntry.getValue();
|
||||
if (value == null) {
|
||||
hasNull.set(true);
|
||||
} else {
|
||||
types.add(value.getClass());
|
||||
args.add(value);
|
||||
}
|
||||
}
|
||||
if (hasNull.get()) {
|
||||
return;
|
||||
}
|
||||
Method declaredMethod;
|
||||
try {
|
||||
declaredMethod = handler.getDeclaredMethod("handler" + s, types.toArray(new Class[0]));
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Object result = declaredMethod.invoke(commandHandler, args.toArray());
|
||||
if (result != null) {
|
||||
channelHandlerContext.writeAndFlush(new TextWebSocketFrame(new JSONObject().fluentPut("op", command).fluentPut("data", result).toJSONString()));
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@SneakyThrows
|
||||
public static void handlerJoin(Class<? extends NettyCommandHandler> handler, NettyCommandHandler commandHandler,ChannelHandlerContext channelHandlerContext) {
|
||||
Method handlerJoin = handler.getDeclaredMethod("handlerJoin", ChannelHandlerContext.class);
|
||||
handlerJoin.invoke(commandHandler, channelHandlerContext);
|
||||
}
|
||||
@SneakyThrows
|
||||
public static void handlerClose(Class<? extends NettyCommandHandler> handler, NettyCommandHandler commandHandler, ChannelHandlerContext channelHandlerContext) {
|
||||
Method handlerJoin = handler.getDeclaredMethod("handlerClose", ChannelHandlerContext.class);
|
||||
handlerJoin.invoke(commandHandler, channelHandlerContext);
|
||||
}
|
||||
@SneakyThrows
|
||||
public static void handlerError(Class<? extends NettyCommandHandler> handler, NettyCommandHandler commandHandler, ChannelHandlerContext channelHandlerContext, Throwable cause) {
|
||||
Method handlerJoin = handler.getDeclaredMethod("handlerError", ChannelHandlerContext.class, Throwable.class);
|
||||
handlerJoin.invoke(commandHandler, channelHandlerContext, cause);
|
||||
}
|
||||
private Class<T> handler;
|
||||
private T obj;
|
||||
@SneakyThrows
|
||||
public NettyUtils(Class<T> handler){
|
||||
this.handler = handler;
|
||||
Constructor<T> constructor = handler.getConstructor();
|
||||
this.obj = constructor.newInstance();
|
||||
}
|
||||
public NettyUtils(Class<T> handler, ConfigurableApplicationContext configurableApplicationContext){
|
||||
this.handler = handler;
|
||||
obj = configurableApplicationContext.getBean(handler);
|
||||
}
|
||||
public void handler(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) {
|
||||
NettyUtils.handler(this.handler, obj, channelHandlerContext, textWebSocketFrame);
|
||||
}
|
||||
|
||||
public void handlerJoin(ChannelHandlerContext channelHandlerContext) {
|
||||
NettyUtils.handlerJoin(this.handler, obj,channelHandlerContext);
|
||||
}
|
||||
|
||||
public void handlerClose(ChannelHandlerContext channelHandlerContext) {
|
||||
NettyUtils.handlerClose(this.handler, obj, channelHandlerContext);
|
||||
}
|
||||
|
||||
public void handlerError(ChannelHandlerContext channelHandlerContext, Throwable cause) {
|
||||
NettyUtils.handlerError(this.handler, obj, channelHandlerContext, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
36
lib-utils/src/main/java/top/xinsin/utils/RData.java
Normal file
36
lib-utils/src/main/java/top/xinsin/utils/RData.java
Normal file
@ -0,0 +1,36 @@
|
||||
package top.xinsin.utils;
|
||||
|
||||
import lombok.Data;
|
||||
import top.xinsin.enums.HttpCodes;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* @version 1.0
|
||||
* Created On 2022/5/14
|
||||
* @param <T> 返回值类型
|
||||
*/
|
||||
@Data
|
||||
public class RData<T> {
|
||||
private int status;
|
||||
private String message;
|
||||
private T data;
|
||||
private long timestamp;
|
||||
|
||||
public RData() {
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
public static<T> RData<T> success(T data){
|
||||
RData<T> rData = new RData<>();
|
||||
rData.setStatus(HttpCodes.HTTP_CODES200.getCode());
|
||||
rData.setMessage(HttpCodes.HTTP_CODES200.getMessage());
|
||||
rData.setData(data);
|
||||
return rData;
|
||||
}
|
||||
public static<T> RData<T> failed(HttpCodes httpCodes, T data){
|
||||
RData<T> rData = new RData<>();
|
||||
rData.setStatus(httpCodes.getCode());
|
||||
rData.setMessage(httpCodes.getMessage());
|
||||
rData.setData(data);
|
||||
return rData;
|
||||
}
|
||||
}
|
137
lib-utils/src/main/java/top/xinsin/utils/ResponseData.java
Normal file
137
lib-utils/src/main/java/top/xinsin/utils/ResponseData.java
Normal file
@ -0,0 +1,137 @@
|
||||
package top.xinsin.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2021/12/16 20:39
|
||||
* @version 1.0
|
||||
*/
|
||||
@Deprecated
|
||||
@Data
|
||||
public class ResponseData {
|
||||
private JSONObject data;
|
||||
private JSONArray array;
|
||||
private String content;
|
||||
private Integer num;
|
||||
private HttpStatus status;
|
||||
|
||||
public ResponseData(JSONObject data){
|
||||
this.data = data;
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(JSONArray data){
|
||||
this.array = data;
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(Map<?,?> data){
|
||||
this.data = JSON.parseObject(JSON.toJSONString(data));
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(List<?> data){
|
||||
this.array = JSON.parseArray(JSON.toJSONString(data));
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(String data){
|
||||
this.content = data;
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(Integer data){
|
||||
this.num = data;
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(int data){
|
||||
this.num = data;
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(Integer data,HttpStatus status) {
|
||||
this.num = data;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(int data,HttpStatus status){
|
||||
this.num = data;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(JSONObject data,HttpStatus status){
|
||||
this.data = data;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(JSONArray data,HttpStatus status){
|
||||
this.array = data;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(Map<?,?> data,HttpStatus status){
|
||||
this.data = JSON.parseObject(JSON.toJSONString(data));
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(List<?> data,HttpStatus status){
|
||||
this.array = JSON.parseArray(JSON.toJSONString(data));
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(String data,HttpStatus status){
|
||||
this.content = data;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(HttpStatus status){
|
||||
this.data = null;
|
||||
this.array = null;
|
||||
this.content = null;
|
||||
this.num = null;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(Object data,HttpStatus status){
|
||||
this.content = data.toString();
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ResponseData(Object data){
|
||||
this.content = data.toString();
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
public ResponseData(){
|
||||
this.data = null;
|
||||
this.array = null;
|
||||
this.content = null;
|
||||
this.status = HttpStatus.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.fluentPut("status",this.status.value())
|
||||
.fluentPut("msg",this.status.getReasonPhrase());
|
||||
if(this.data != null) {
|
||||
jsonObject.fluentPut("data", data);
|
||||
}else if(this.array != null){
|
||||
jsonObject.fluentPut("data",array);
|
||||
}else if(this.content != null){
|
||||
jsonObject.fluentPut("data",content);
|
||||
}else if(this.num != null){
|
||||
jsonObject.fluentPut("data",num);
|
||||
}
|
||||
return jsonObject.toJSONString();
|
||||
}
|
||||
}
|
29
lib-utils/src/main/java/top/xinsin/utils/SqlUtils.java
Normal file
29
lib-utils/src/main/java/top/xinsin/utils/SqlUtils.java
Normal file
@ -0,0 +1,29 @@
|
||||
package top.xinsin.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
|
||||
/**
|
||||
* @author xinsin
|
||||
* @version 1.0.0
|
||||
* Created On 2022/5/14
|
||||
*/
|
||||
public class SqlUtils {
|
||||
public static JSONObject insertOperate(int i){
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
if (i >= 1){
|
||||
jsonObject.fluentPut("affected_rows",i);
|
||||
}else{
|
||||
jsonObject.fluentPut("affected rows","error");
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
public static JSONObject updateOperate(int i){
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
if (i >= 0){
|
||||
jsonObject.fluentPut("affected_rows",i);
|
||||
}else{
|
||||
jsonObject.fluentPut("affected rows","error");
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
51
lib-voice/pom.xml
Normal file
51
lib-voice/pom.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>witsTalk</artifactId>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lib-voice</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>top.xinsin</groupId>
|
||||
<artifactId>lib-utils</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!--netty框架依赖-->
|
||||
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.86.Final</version>
|
||||
</dependency>
|
||||
<!--spring-boot web模块-->
|
||||
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<!--<directory>..\target</directory>-->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<!--suppress MavenModelInspection -->
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
35
lib-voice/src/main/java/cn/wzpmc/VoiceFrameHandler.java
Normal file
35
lib-voice/src/main/java/cn/wzpmc/VoiceFrameHandler.java
Normal file
@ -0,0 +1,35 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
import cn.wzpmc.services.VoiceCommandHandler;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.xinsin.utils.NettyUtils;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
@ChannelHandler.Sharable
|
||||
public class VoiceFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||
private final NettyUtils<VoiceCommandHandler> commandHandler = new NettyUtils<>(VoiceCommandHandler.class);
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) {
|
||||
commandHandler.handler(channelHandlerContext, textWebSocketFrame);
|
||||
}
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext channelHandlerContext){
|
||||
commandHandler.handlerJoin(channelHandlerContext);
|
||||
}
|
||||
@Override
|
||||
public void handlerRemoved(ChannelHandlerContext channelHandlerContext) {
|
||||
commandHandler.handlerClose(channelHandlerContext);
|
||||
}
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext channelHandlerContext,Throwable throwable) {
|
||||
commandHandler.handlerError(channelHandlerContext, throwable);
|
||||
}
|
||||
}
|
37
lib-voice/src/main/java/cn/wzpmc/VoiceHandler.java
Normal file
37
lib-voice/src/main/java/cn/wzpmc/VoiceHandler.java
Normal file
@ -0,0 +1,37 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
public class VoiceHandler extends ChannelInitializer<SocketChannel> {
|
||||
private final VoiceFrameHandler voiceFrameHandler;
|
||||
@Autowired
|
||||
public VoiceHandler(VoiceFrameHandler voiceFrameHandler){
|
||||
this.voiceFrameHandler = voiceFrameHandler;
|
||||
}
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel){
|
||||
ChannelPipeline pipeline = socketChannel.pipeline();
|
||||
pipeline.addLast(new LoggingHandler(LogLevel.DEBUG))
|
||||
.addLast(new HttpServerCodec())
|
||||
.addLast(new ChunkedWriteHandler())
|
||||
.addLast(new HttpObjectAggregator(16384))
|
||||
.addLast(new WebSocketServerProtocolHandler("/voice"))
|
||||
.addLast(voiceFrameHandler);
|
||||
}
|
||||
}
|
62
lib-voice/src/main/java/cn/wzpmc/VoiceNetty.java
Normal file
62
lib-voice/src/main/java/cn/wzpmc/VoiceNetty.java
Normal file
@ -0,0 +1,62 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class VoiceNetty implements ApplicationListener<ContextClosedEvent> {
|
||||
private final EventLoopGroup boss = new NioEventLoopGroup();
|
||||
private final EventLoopGroup worker = new NioEventLoopGroup();
|
||||
@Value("${server.port}")
|
||||
private int port;
|
||||
private Channel channel;
|
||||
private final VoiceHandler voiceHandler;
|
||||
@Autowired
|
||||
public VoiceNetty(VoiceHandler voiceNetty){
|
||||
this.voiceHandler = voiceNetty;
|
||||
}
|
||||
public void start(){
|
||||
try{
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
bootstrap
|
||||
.group(boss,worker)
|
||||
.handler(new LoggingHandler(LogLevel.DEBUG))
|
||||
.childHandler(voiceHandler)
|
||||
.channel(NioServerSocketChannel.class);
|
||||
ChannelFuture channelFuture = bootstrap.bind(new InetSocketAddress(port)).sync();
|
||||
if (channelFuture.isSuccess()){
|
||||
log.info("Voice Server started on 0.0.0.0:{}",port);
|
||||
}
|
||||
this.channel = channelFuture.channel();
|
||||
this.channel.closeFuture().sync();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
log.info("Shutdown Netty Server...");
|
||||
if(channel != null) {
|
||||
channel.close();
|
||||
}
|
||||
boss.shutdownGracefully();
|
||||
worker.shutdownGracefully();
|
||||
log.info("Shutdown Netty Server Success!");
|
||||
}
|
||||
}
|
26
lib-voice/src/main/java/cn/wzpmc/VoiceStart.java
Normal file
26
lib-voice/src/main/java/cn/wzpmc/VoiceStart.java
Normal file
@ -0,0 +1,26 @@
|
||||
package cn.wzpmc;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author wzp
|
||||
* Created On 2022/5/14
|
||||
* @version 1.0
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class VoiceStart {
|
||||
private static VoiceNetty voiceNetty;
|
||||
@Autowired
|
||||
public VoiceStart(VoiceNetty voiceNetty){
|
||||
VoiceStart.voiceNetty = voiceNetty;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication springApplication = new SpringApplication(VoiceStart.class);
|
||||
springApplication.run(args);
|
||||
springApplication.addListeners(voiceNetty);
|
||||
voiceNetty.start();
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package cn.wzpmc.services;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.auth0.jwt.interfaces.Claim;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelId;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.xinsin.interfaces.NettyCommandHandler;
|
||||
import top.xinsin.utils.JwtTokenUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class VoiceCommandHandler implements NettyCommandHandler {
|
||||
/**
|
||||
* 用于保存用户的ChannelId和username
|
||||
* key 为 ChannelId
|
||||
* value 为 username
|
||||
*/
|
||||
private final Map<ChannelId, String> usernames = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 用于保存用户的mediaId和username
|
||||
* key 为 username
|
||||
* value 为 mediaId
|
||||
*/
|
||||
private final Map<String, String> userMedias = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 用于保存ChannelId和Channel
|
||||
* key 为 ChannelId
|
||||
* value 为 Channel
|
||||
*/
|
||||
public final Map<ChannelId, Channel> users = new ConcurrentHashMap<>();
|
||||
public JSONObject handlerLogin(ChannelHandlerContext channelHandlerContext, String token, String media){
|
||||
Boolean right = JwtTokenUtils.isRight(token);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.fluentPut("success", right);
|
||||
if (right) {
|
||||
DecodedJWT tokenInfo = JwtTokenUtils.getTokenInfo(token);
|
||||
Claim username = tokenInfo.getClaim("username");
|
||||
String s = username.asString();
|
||||
ChannelId id = channelHandlerContext.channel().id();
|
||||
usernames.put(id, s);
|
||||
userMedias.put(s, media);
|
||||
JSONObject toAll = new JSONObject();
|
||||
toAll.fluentPut("op","uadd").fluentPut("username", s).fluentPut("mediaId", media);
|
||||
for (Map.Entry<ChannelId, Channel> channelIdChannelEntry : users.entrySet()) {
|
||||
ChannelId key = channelIdChannelEntry.getKey();
|
||||
Channel value = channelIdChannelEntry.getValue();
|
||||
if (!id.equals(key)){
|
||||
value.writeAndFlush(new TextWebSocketFrame(toAll.toJSONString()));
|
||||
}
|
||||
}
|
||||
jsonObject.fluentPut("username", s);
|
||||
HashMap<String, String> resultHashMap = new HashMap<>();
|
||||
for (Map.Entry<String, String> stringStringEntry : userMedias.entrySet()) {
|
||||
String key = stringStringEntry.getKey();
|
||||
if (!s.equals(key)) {
|
||||
resultHashMap.put(key, stringStringEntry.getValue());
|
||||
}
|
||||
}
|
||||
jsonObject.fluentPut("data", resultHashMap);
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
public void handlerOffer(ChannelHandlerContext channelHandlerContext,JSONObject data,String username){
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
log.info("{} -> {} <=offer=> {}", usernames.get(id), username, data);
|
||||
String from = usernames.get(id);
|
||||
JSONObject send = new JSONObject().fluentPut("op", "offer").fluentPut("from", from).fluentPut("data", data);
|
||||
sendTo(username, send);
|
||||
}
|
||||
public void handlerCandidate(ChannelHandlerContext channelHandlerContext,JSONObject data,String username){
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
log.info("{} -> {} <=candidate=> {}", usernames.get(id), username, data);
|
||||
String from = usernames.get(id);
|
||||
JSONObject send = new JSONObject().fluentPut("op", "candidate").fluentPut("from", from).fluentPut("data", data);
|
||||
sendTo(username, send);
|
||||
}
|
||||
public void handlerAnswer(ChannelHandlerContext channelHandlerContext,JSONObject data,String username){
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
log.info("{} -> {} <=answer=> {}", usernames.get(id), username, data);
|
||||
String from = usernames.get(id);
|
||||
JSONObject send = new JSONObject().fluentPut("op", "answer").fluentPut("from", from).fluentPut("data", data);
|
||||
sendTo(username, send);
|
||||
}
|
||||
public void handlerPing(ChannelHandlerContext channelHandlerContext){
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.fluentPut("op", "pong").fluentPut("data",new JSONObject().fluentPut("time", System.currentTimeMillis()));
|
||||
channel.writeAndFlush(new TextWebSocketFrame(jsonObject.toJSONString()));
|
||||
}
|
||||
private void sendTo(String username,JSONObject send){
|
||||
for (Map.Entry<ChannelId, String> entry : usernames.entrySet()) {
|
||||
if (entry.getValue().equals(username)) {
|
||||
Channel toChannel = users.get(entry.getKey());
|
||||
toChannel.writeAndFlush(new TextWebSocketFrame(send.toJSONString()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void handlerClose(ChannelHandlerContext channelHandlerContext) {
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
String username = usernames.get(id);
|
||||
usernames.remove(id);
|
||||
JSONObject leaveObject = new JSONObject();
|
||||
leaveObject.fluentPut("op", "leave").fluentPut("mediaId", userMedias.get(username)).fluentPut("username", username);
|
||||
for (Map.Entry<ChannelId, Channel> channelIdChannelEntry : users.entrySet()) {
|
||||
channelIdChannelEntry.getValue().writeAndFlush(new TextWebSocketFrame(leaveObject.toJSONString()));
|
||||
}
|
||||
userMedias.remove(username);
|
||||
users.remove(id);
|
||||
log.info("User {} disconnected with channel {}", channel.remoteAddress(), id.asShortText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerJoin(ChannelHandlerContext channelHandlerContext) {
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
users.put(id, channel);
|
||||
log.info("User {} connected with channel {}", channel.remoteAddress(), id.asShortText());
|
||||
}
|
||||
public void handlerError(ChannelHandlerContext channelHandlerContext, Throwable cause){
|
||||
Channel channel = channelHandlerContext.channel();
|
||||
ChannelId id = channel.id();
|
||||
channelHandlerContext.close();
|
||||
users.remove(id);
|
||||
log.info("User {} had an error with channel {}", channel.remoteAddress(), id.asShortText());
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
2
lib-voice/src/main/resources/application.yml
Normal file
2
lib-voice/src/main/resources/application.yml
Normal file
@ -0,0 +1,2 @@
|
||||
server:
|
||||
port: 8006
|
26
nginx-1.20.2/conf/fastcgi.conf
Normal file
26
nginx-1.20.2/conf/fastcgi.conf
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param QUERY_STRING $query_string;
|
||||
fastcgi_param REQUEST_METHOD $request_method;
|
||||
fastcgi_param CONTENT_TYPE $content_type;
|
||||
fastcgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_param REQUEST_URI $request_uri;
|
||||
fastcgi_param DOCUMENT_URI $document_uri;
|
||||
fastcgi_param DOCUMENT_ROOT $document_root;
|
||||
fastcgi_param SERVER_PROTOCOL $server_protocol;
|
||||
fastcgi_param REQUEST_SCHEME $scheme;
|
||||
fastcgi_param HTTPS $https if_not_empty;
|
||||
|
||||
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
|
||||
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||
|
||||
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||
fastcgi_param REMOTE_PORT $remote_port;
|
||||
fastcgi_param SERVER_ADDR $server_addr;
|
||||
fastcgi_param SERVER_PORT $server_port;
|
||||
fastcgi_param SERVER_NAME $server_name;
|
||||
|
||||
# PHP only, required if PHP was built with --enable-force-cgi-redirect
|
||||
fastcgi_param REDIRECT_STATUS 200;
|
25
nginx-1.20.2/conf/fastcgi_params
Normal file
25
nginx-1.20.2/conf/fastcgi_params
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
fastcgi_param QUERY_STRING $query_string;
|
||||
fastcgi_param REQUEST_METHOD $request_method;
|
||||
fastcgi_param CONTENT_TYPE $content_type;
|
||||
fastcgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_param REQUEST_URI $request_uri;
|
||||
fastcgi_param DOCUMENT_URI $document_uri;
|
||||
fastcgi_param DOCUMENT_ROOT $document_root;
|
||||
fastcgi_param SERVER_PROTOCOL $server_protocol;
|
||||
fastcgi_param REQUEST_SCHEME $scheme;
|
||||
fastcgi_param HTTPS $https if_not_empty;
|
||||
|
||||
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
|
||||
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||
|
||||
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||
fastcgi_param REMOTE_PORT $remote_port;
|
||||
fastcgi_param SERVER_ADDR $server_addr;
|
||||
fastcgi_param SERVER_PORT $server_port;
|
||||
fastcgi_param SERVER_NAME $server_name;
|
||||
|
||||
# PHP only, required if PHP was built with --enable-force-cgi-redirect
|
||||
fastcgi_param REDIRECT_STATUS 200;
|
109
nginx-1.20.2/conf/koi-utf
Normal file
109
nginx-1.20.2/conf/koi-utf
Normal file
@ -0,0 +1,109 @@
|
||||
|
||||
# This map is not a full koi8-r <> utf8 map: it does not contain
|
||||
# box-drawing and some other characters. Besides this map contains
|
||||
# several koi8-u and Byelorussian letters which are not in koi8-r.
|
||||
# If you need a full and standard map, use contrib/unicode2nginx/koi-utf
|
||||
# map instead.
|
||||
|
||||
charset_map koi8-r utf-8 {
|
||||
|
||||
80 E282AC ; # euro
|
||||
|
||||
95 E280A2 ; # bullet
|
||||
|
||||
9A C2A0 ; #
|
||||
|
||||
9E C2B7 ; # ·
|
||||
|
||||
A3 D191 ; # small yo
|
||||
A4 D194 ; # small Ukrainian ye
|
||||
|
||||
A6 D196 ; # small Ukrainian i
|
||||
A7 D197 ; # small Ukrainian yi
|
||||
|
||||
AD D291 ; # small Ukrainian soft g
|
||||
AE D19E ; # small Byelorussian short u
|
||||
|
||||
B0 C2B0 ; # °
|
||||
|
||||
B3 D081 ; # capital YO
|
||||
B4 D084 ; # capital Ukrainian YE
|
||||
|
||||
B6 D086 ; # capital Ukrainian I
|
||||
B7 D087 ; # capital Ukrainian YI
|
||||
|
||||
B9 E28496 ; # numero sign
|
||||
|
||||
BD D290 ; # capital Ukrainian soft G
|
||||
BE D18E ; # capital Byelorussian short U
|
||||
|
||||
BF C2A9 ; # (C)
|
||||
|
||||
C0 D18E ; # small yu
|
||||
C1 D0B0 ; # small a
|
||||
C2 D0B1 ; # small b
|
||||
C3 D186 ; # small ts
|
||||
C4 D0B4 ; # small d
|
||||
C5 D0B5 ; # small ye
|
||||
C6 D184 ; # small f
|
||||
C7 D0B3 ; # small g
|
||||
C8 D185 ; # small kh
|
||||
C9 D0B8 ; # small i
|
||||
CA D0B9 ; # small j
|
||||
CB D0BA ; # small k
|
||||
CC D0BB ; # small l
|
||||
CD D0BC ; # small m
|
||||
CE D0BD ; # small n
|
||||
CF D0BE ; # small o
|
||||
|
||||
D0 D0BF ; # small p
|
||||
D1 D18F ; # small ya
|
||||
D2 D180 ; # small r
|
||||
D3 D181 ; # small s
|
||||
D4 D182 ; # small t
|
||||
D5 D183 ; # small u
|
||||
D6 D0B6 ; # small zh
|
||||
D7 D0B2 ; # small v
|
||||
D8 D18C ; # small soft sign
|
||||
D9 D18B ; # small y
|
||||
DA D0B7 ; # small z
|
||||
DB D188 ; # small sh
|
||||
DC D18D ; # small e
|
||||
DD D189 ; # small shch
|
||||
DE D187 ; # small ch
|
||||
DF D18A ; # small hard sign
|
||||
|
||||
E0 D0AE ; # capital YU
|
||||
E1 D090 ; # capital A
|
||||
E2 D091 ; # capital B
|
||||
E3 D0A6 ; # capital TS
|
||||
E4 D094 ; # capital D
|
||||
E5 D095 ; # capital YE
|
||||
E6 D0A4 ; # capital F
|
||||
E7 D093 ; # capital G
|
||||
E8 D0A5 ; # capital KH
|
||||
E9 D098 ; # capital I
|
||||
EA D099 ; # capital J
|
||||
EB D09A ; # capital K
|
||||
EC D09B ; # capital L
|
||||
ED D09C ; # capital M
|
||||
EE D09D ; # capital N
|
||||
EF D09E ; # capital O
|
||||
|
||||
F0 D09F ; # capital P
|
||||
F1 D0AF ; # capital YA
|
||||
F2 D0A0 ; # capital R
|
||||
F3 D0A1 ; # capital S
|
||||
F4 D0A2 ; # capital T
|
||||
F5 D0A3 ; # capital U
|
||||
F6 D096 ; # capital ZH
|
||||
F7 D092 ; # capital V
|
||||
F8 D0AC ; # capital soft sign
|
||||
F9 D0AB ; # capital Y
|
||||
FA D097 ; # capital Z
|
||||
FB D0A8 ; # capital SH
|
||||
FC D0AD ; # capital E
|
||||
FD D0A9 ; # capital SHCH
|
||||
FE D0A7 ; # capital CH
|
||||
FF D0AA ; # capital hard sign
|
||||
}
|
103
nginx-1.20.2/conf/koi-win
Normal file
103
nginx-1.20.2/conf/koi-win
Normal file
@ -0,0 +1,103 @@
|
||||
|
||||
charset_map koi8-r windows-1251 {
|
||||
|
||||
80 88 ; # euro
|
||||
|
||||
95 95 ; # bullet
|
||||
|
||||
9A A0 ; #
|
||||
|
||||
9E B7 ; # ·
|
||||
|
||||
A3 B8 ; # small yo
|
||||
A4 BA ; # small Ukrainian ye
|
||||
|
||||
A6 B3 ; # small Ukrainian i
|
||||
A7 BF ; # small Ukrainian yi
|
||||
|
||||
AD B4 ; # small Ukrainian soft g
|
||||
AE A2 ; # small Byelorussian short u
|
||||
|
||||
B0 B0 ; # °
|
||||
|
||||
B3 A8 ; # capital YO
|
||||
B4 AA ; # capital Ukrainian YE
|
||||
|
||||
B6 B2 ; # capital Ukrainian I
|
||||
B7 AF ; # capital Ukrainian YI
|
||||
|
||||
B9 B9 ; # numero sign
|
||||
|
||||
BD A5 ; # capital Ukrainian soft G
|
||||
BE A1 ; # capital Byelorussian short U
|
||||
|
||||
BF A9 ; # (C)
|
||||
|
||||
C0 FE ; # small yu
|
||||
C1 E0 ; # small a
|
||||
C2 E1 ; # small b
|
||||
C3 F6 ; # small ts
|
||||
C4 E4 ; # small d
|
||||
C5 E5 ; # small ye
|
||||
C6 F4 ; # small f
|
||||
C7 E3 ; # small g
|
||||
C8 F5 ; # small kh
|
||||
C9 E8 ; # small i
|
||||
CA E9 ; # small j
|
||||
CB EA ; # small k
|
||||
CC EB ; # small l
|
||||
CD EC ; # small m
|
||||
CE ED ; # small n
|
||||
CF EE ; # small o
|
||||
|
||||
D0 EF ; # small p
|
||||
D1 FF ; # small ya
|
||||
D2 F0 ; # small r
|
||||
D3 F1 ; # small s
|
||||
D4 F2 ; # small t
|
||||
D5 F3 ; # small u
|
||||
D6 E6 ; # small zh
|
||||
D7 E2 ; # small v
|
||||
D8 FC ; # small soft sign
|
||||
D9 FB ; # small y
|
||||
DA E7 ; # small z
|
||||
DB F8 ; # small sh
|
||||
DC FD ; # small e
|
||||
DD F9 ; # small shch
|
||||
DE F7 ; # small ch
|
||||
DF FA ; # small hard sign
|
||||
|
||||
E0 DE ; # capital YU
|
||||
E1 C0 ; # capital A
|
||||
E2 C1 ; # capital B
|
||||
E3 D6 ; # capital TS
|
||||
E4 C4 ; # capital D
|
||||
E5 C5 ; # capital YE
|
||||
E6 D4 ; # capital F
|
||||
E7 C3 ; # capital G
|
||||
E8 D5 ; # capital KH
|
||||
E9 C8 ; # capital I
|
||||
EA C9 ; # capital J
|
||||
EB CA ; # capital K
|
||||
EC CB ; # capital L
|
||||
ED CC ; # capital M
|
||||
EE CD ; # capital N
|
||||
EF CE ; # capital O
|
||||
|
||||
F0 CF ; # capital P
|
||||
F1 DF ; # capital YA
|
||||
F2 D0 ; # capital R
|
||||
F3 D1 ; # capital S
|
||||
F4 D2 ; # capital T
|
||||
F5 D3 ; # capital U
|
||||
F6 C6 ; # capital ZH
|
||||
F7 C2 ; # capital V
|
||||
F8 DC ; # capital soft sign
|
||||
F9 DB ; # capital Y
|
||||
FA C7 ; # capital Z
|
||||
FB D8 ; # capital SH
|
||||
FC DD ; # capital E
|
||||
FD D9 ; # capital SHCH
|
||||
FE D7 ; # capital CH
|
||||
FF DA ; # capital hard sign
|
||||
}
|
97
nginx-1.20.2/conf/mime.types
Normal file
97
nginx-1.20.2/conf/mime.types
Normal file
@ -0,0 +1,97 @@
|
||||
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
83
nginx-1.20.2/conf/nginx.conf
Normal file
83
nginx-1.20.2/conf/nginx.conf
Normal file
@ -0,0 +1,83 @@
|
||||
|
||||
#user nobody;
|
||||
worker_processes 1;
|
||||
|
||||
#error_log logs/error.log;
|
||||
#error_log logs/error.log notice;
|
||||
#error_log logs/error.log info;
|
||||
|
||||
#pid logs/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
# '$status $body_bytes_sent "$http_referer" '
|
||||
# '"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
#access_log logs/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
charset utf-8;
|
||||
# access_log logs/host.access.log main;
|
||||
|
||||
# 代理前端vue
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass http://127.0.0.1:8081;
|
||||
}
|
||||
# 代理user服务器
|
||||
location /user {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass http://127.0.0.1:8003;
|
||||
}
|
||||
# 代理文件服务器
|
||||
location /file {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass http://127.0.0.1:8004;
|
||||
}
|
||||
# 代理chat服务器
|
||||
location /chat {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass http://127.0.0.1:8005;
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
}
|
||||
# 代理voice服务器
|
||||
location /voice {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass http://127.0.0.1:8006;
|
||||
proxy_connect_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
}
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root html;
|
||||
}
|
||||
}
|
||||
}
|
17
nginx-1.20.2/conf/scgi_params
Normal file
17
nginx-1.20.2/conf/scgi_params
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
scgi_param REQUEST_METHOD $request_method;
|
||||
scgi_param REQUEST_URI $request_uri;
|
||||
scgi_param QUERY_STRING $query_string;
|
||||
scgi_param CONTENT_TYPE $content_type;
|
||||
|
||||
scgi_param DOCUMENT_URI $document_uri;
|
||||
scgi_param DOCUMENT_ROOT $document_root;
|
||||
scgi_param SCGI 1;
|
||||
scgi_param SERVER_PROTOCOL $server_protocol;
|
||||
scgi_param REQUEST_SCHEME $scheme;
|
||||
scgi_param HTTPS $https if_not_empty;
|
||||
|
||||
scgi_param REMOTE_ADDR $remote_addr;
|
||||
scgi_param REMOTE_PORT $remote_port;
|
||||
scgi_param SERVER_PORT $server_port;
|
||||
scgi_param SERVER_NAME $server_name;
|
17
nginx-1.20.2/conf/uwsgi_params
Normal file
17
nginx-1.20.2/conf/uwsgi_params
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
uwsgi_param QUERY_STRING $query_string;
|
||||
uwsgi_param REQUEST_METHOD $request_method;
|
||||
uwsgi_param CONTENT_TYPE $content_type;
|
||||
uwsgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
uwsgi_param REQUEST_URI $request_uri;
|
||||
uwsgi_param PATH_INFO $document_uri;
|
||||
uwsgi_param DOCUMENT_ROOT $document_root;
|
||||
uwsgi_param SERVER_PROTOCOL $server_protocol;
|
||||
uwsgi_param REQUEST_SCHEME $scheme;
|
||||
uwsgi_param HTTPS $https if_not_empty;
|
||||
|
||||
uwsgi_param REMOTE_ADDR $remote_addr;
|
||||
uwsgi_param REMOTE_PORT $remote_port;
|
||||
uwsgi_param SERVER_PORT $server_port;
|
||||
uwsgi_param SERVER_NAME $server_name;
|
126
nginx-1.20.2/conf/win-utf
Normal file
126
nginx-1.20.2/conf/win-utf
Normal file
@ -0,0 +1,126 @@
|
||||
|
||||
# This map is not a full windows-1251 <> utf8 map: it does not
|
||||
# contain Serbian and Macedonian letters. If you need a full map,
|
||||
# use contrib/unicode2nginx/win-utf map instead.
|
||||
|
||||
charset_map windows-1251 utf-8 {
|
||||
|
||||
82 E2809A ; # single low-9 quotation mark
|
||||
|
||||
84 E2809E ; # double low-9 quotation mark
|
||||
85 E280A6 ; # ellipsis
|
||||
86 E280A0 ; # dagger
|
||||
87 E280A1 ; # double dagger
|
||||
88 E282AC ; # euro
|
||||
89 E280B0 ; # per mille
|
||||
|
||||
91 E28098 ; # left single quotation mark
|
||||
92 E28099 ; # right single quotation mark
|
||||
93 E2809C ; # left double quotation mark
|
||||
94 E2809D ; # right double quotation mark
|
||||
95 E280A2 ; # bullet
|
||||
96 E28093 ; # en dash
|
||||
97 E28094 ; # em dash
|
||||
|
||||
99 E284A2 ; # trade mark sign
|
||||
|
||||
A0 C2A0 ; #
|
||||
A1 D18E ; # capital Byelorussian short U
|
||||
A2 D19E ; # small Byelorussian short u
|
||||
|
||||
A4 C2A4 ; # currency sign
|
||||
A5 D290 ; # capital Ukrainian soft G
|
||||
A6 C2A6 ; # borken bar
|
||||
A7 C2A7 ; # section sign
|
||||
A8 D081 ; # capital YO
|
||||
A9 C2A9 ; # (C)
|
||||
AA D084 ; # capital Ukrainian YE
|
||||
AB C2AB ; # left-pointing double angle quotation mark
|
||||
AC C2AC ; # not sign
|
||||
AD C2AD ; # soft hypen
|
||||
AE C2AE ; # (R)
|
||||
AF D087 ; # capital Ukrainian YI
|
||||
|
||||
B0 C2B0 ; # °
|
||||
B1 C2B1 ; # plus-minus sign
|
||||
B2 D086 ; # capital Ukrainian I
|
||||
B3 D196 ; # small Ukrainian i
|
||||
B4 D291 ; # small Ukrainian soft g
|
||||
B5 C2B5 ; # micro sign
|
||||
B6 C2B6 ; # pilcrow sign
|
||||
B7 C2B7 ; # ·
|
||||
B8 D191 ; # small yo
|
||||
B9 E28496 ; # numero sign
|
||||
BA D194 ; # small Ukrainian ye
|
||||
BB C2BB ; # right-pointing double angle quotation mark
|
||||
|
||||
BF D197 ; # small Ukrainian yi
|
||||
|
||||
C0 D090 ; # capital A
|
||||
C1 D091 ; # capital B
|
||||
C2 D092 ; # capital V
|
||||
C3 D093 ; # capital G
|
||||
C4 D094 ; # capital D
|
||||
C5 D095 ; # capital YE
|
||||
C6 D096 ; # capital ZH
|
||||
C7 D097 ; # capital Z
|
||||
C8 D098 ; # capital I
|
||||
C9 D099 ; # capital J
|
||||
CA D09A ; # capital K
|
||||
CB D09B ; # capital L
|
||||
CC D09C ; # capital M
|
||||
CD D09D ; # capital N
|
||||
CE D09E ; # capital O
|
||||
CF D09F ; # capital P
|
||||
|
||||
D0 D0A0 ; # capital R
|
||||
D1 D0A1 ; # capital S
|
||||
D2 D0A2 ; # capital T
|
||||
D3 D0A3 ; # capital U
|
||||
D4 D0A4 ; # capital F
|
||||
D5 D0A5 ; # capital KH
|
||||
D6 D0A6 ; # capital TS
|
||||
D7 D0A7 ; # capital CH
|
||||
D8 D0A8 ; # capital SH
|
||||
D9 D0A9 ; # capital SHCH
|
||||
DA D0AA ; # capital hard sign
|
||||
DB D0AB ; # capital Y
|
||||
DC D0AC ; # capital soft sign
|
||||
DD D0AD ; # capital E
|
||||
DE D0AE ; # capital YU
|
||||
DF D0AF ; # capital YA
|
||||
|
||||
E0 D0B0 ; # small a
|
||||
E1 D0B1 ; # small b
|
||||
E2 D0B2 ; # small v
|
||||
E3 D0B3 ; # small g
|
||||
E4 D0B4 ; # small d
|
||||
E5 D0B5 ; # small ye
|
||||
E6 D0B6 ; # small zh
|
||||
E7 D0B7 ; # small z
|
||||
E8 D0B8 ; # small i
|
||||
E9 D0B9 ; # small j
|
||||
EA D0BA ; # small k
|
||||
EB D0BB ; # small l
|
||||
EC D0BC ; # small m
|
||||
ED D0BD ; # small n
|
||||
EE D0BE ; # small o
|
||||
EF D0BF ; # small p
|
||||
|
||||
F0 D180 ; # small r
|
||||
F1 D181 ; # small s
|
||||
F2 D182 ; # small t
|
||||
F3 D183 ; # small u
|
||||
F4 D184 ; # small f
|
||||
F5 D185 ; # small kh
|
||||
F6 D186 ; # small ts
|
||||
F7 D187 ; # small ch
|
||||
F8 D188 ; # small sh
|
||||
F9 D189 ; # small shch
|
||||
FA D18A ; # small hard sign
|
||||
FB D18B ; # small y
|
||||
FC D18C ; # small soft sign
|
||||
FD D18D ; # small e
|
||||
FE D18E ; # small yu
|
||||
FF D18F ; # small ya
|
||||
}
|
21
nginx-1.20.2/contrib/README
Normal file
21
nginx-1.20.2/contrib/README
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
geo2nginx.pl by Andrei Nigmatulin
|
||||
|
||||
The perl script to convert CSV geoip database ( free download
|
||||
at http://www.maxmind.com/app/geoip_country ) to format, suitable
|
||||
for use by the ngx_http_geo_module.
|
||||
|
||||
|
||||
unicode2nginx by Maxim Dounin
|
||||
|
||||
The perl script to convert unicode mappings ( available
|
||||
at http://www.unicode.org/Public/MAPPINGS/ ) to the nginx
|
||||
configuration file format.
|
||||
Two generated full maps for windows-1251 and koi8-r.
|
||||
|
||||
|
||||
vim by Evan Miller
|
||||
|
||||
Syntax highlighting of nginx configuration for vim, to be
|
||||
placed into ~/.vim/.
|
||||
|
58
nginx-1.20.2/contrib/geo2nginx.pl
Normal file
58
nginx-1.20.2/contrib/geo2nginx.pl
Normal file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# (c) Andrei Nigmatulin, 2005
|
||||
#
|
||||
# this script provided "as is", without any warranties. use it at your own risk.
|
||||
#
|
||||
# special thanx to Andrew Sitnikov for perl port
|
||||
#
|
||||
# this script converts CSV geoip database (free download at http://www.maxmind.com/app/geoip_country)
|
||||
# to format, suitable for use with nginx_http_geo module (http://sysoev.ru/nginx)
|
||||
#
|
||||
# for example, line with ip range
|
||||
#
|
||||
# "62.16.68.0","62.16.127.255","1041253376","1041268735","RU","Russian Federation"
|
||||
#
|
||||
# will be converted to four subnetworks:
|
||||
#
|
||||
# 62.16.68.0/22 RU;
|
||||
# 62.16.72.0/21 RU;
|
||||
# 62.16.80.0/20 RU;
|
||||
# 62.16.96.0/19 RU;
|
||||
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
while( <STDIN> ){
|
||||
if (/"[^"]+","[^"]+","([^"]+)","([^"]+)","([^"]+)"/){
|
||||
print_subnets($1, $2, $3);
|
||||
}
|
||||
}
|
||||
|
||||
sub print_subnets {
|
||||
my ($a1, $a2, $c) = @_;
|
||||
my $l;
|
||||
while ($a1 <= $a2) {
|
||||
for ($l = 0; ($a1 & (1 << $l)) == 0 && ($a1 + ((1 << ($l + 1)) - 1)) <= $a2; $l++){};
|
||||
print long2ip($a1) . "/" . (32 - $l) . " " . $c . ";\n";
|
||||
$a1 += (1 << $l);
|
||||
}
|
||||
}
|
||||
|
||||
sub long2ip {
|
||||
my $ip = shift;
|
||||
|
||||
my $str = 0;
|
||||
|
||||
$str = ($ip & 255);
|
||||
|
||||
$ip >>= 8;
|
||||
$str = ($ip & 255).".$str";
|
||||
|
||||
$ip >>= 8;
|
||||
$str = ($ip & 255).".$str";
|
||||
|
||||
$ip >>= 8;
|
||||
$str = ($ip & 255).".$str";
|
||||
}
|
131
nginx-1.20.2/contrib/unicode2nginx/koi-utf
Normal file
131
nginx-1.20.2/contrib/unicode2nginx/koi-utf
Normal file
@ -0,0 +1,131 @@
|
||||
charset_map koi8-r utf-8 {
|
||||
|
||||
80 E29480 ; # BOX DRAWINGS LIGHT HORIZONTAL
|
||||
81 E29482 ; # BOX DRAWINGS LIGHT VERTICAL
|
||||
82 E2948C ; # BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||
83 E29490 ; # BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||
84 E29494 ; # BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
85 E29498 ; # BOX DRAWINGS LIGHT UP AND LEFT
|
||||
86 E2949C ; # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
87 E294A4 ; # BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||
88 E294AC ; # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||
89 E294B4 ; # BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||
8A E294BC ; # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||
8B E29680 ; # UPPER HALF BLOCK
|
||||
8C E29684 ; # LOWER HALF BLOCK
|
||||
8D E29688 ; # FULL BLOCK
|
||||
8E E2968C ; # LEFT HALF BLOCK
|
||||
8F E29690 ; # RIGHT HALF BLOCK
|
||||
90 E29691 ; # LIGHT SHADE
|
||||
91 E29692 ; # MEDIUM SHADE
|
||||
92 E29693 ; # DARK SHADE
|
||||
93 E28CA0 ; # TOP HALF INTEGRAL
|
||||
94 E296A0 ; # BLACK SQUARE
|
||||
95 E28899 ; # BULLET OPERATOR
|
||||
96 E2889A ; # SQUARE ROOT
|
||||
97 E28988 ; # ALMOST EQUAL TO
|
||||
98 E289A4 ; # LESS-THAN OR EQUAL TO
|
||||
99 E289A5 ; # GREATER-THAN OR EQUAL TO
|
||||
9A C2A0 ; # NO-BREAK SPACE
|
||||
9B E28CA1 ; # BOTTOM HALF INTEGRAL
|
||||
9C C2B0 ; # DEGREE SIGN
|
||||
9D C2B2 ; # SUPERSCRIPT TWO
|
||||
9E C2B7 ; # MIDDLE DOT
|
||||
9F C3B7 ; # DIVISION SIGN
|
||||
A0 E29590 ; # BOX DRAWINGS DOUBLE HORIZONTAL
|
||||
A1 E29591 ; # BOX DRAWINGS DOUBLE VERTICAL
|
||||
A2 E29592 ; # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
|
||||
A3 D191 ; # CYRILLIC SMALL LETTER IO
|
||||
A4 E29593 ; # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
|
||||
A5 E29594 ; # BOX DRAWINGS DOUBLE DOWN AND RIGHT
|
||||
A6 E29595 ; # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
|
||||
A7 E29596 ; # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
|
||||
A8 E29597 ; # BOX DRAWINGS DOUBLE DOWN AND LEFT
|
||||
A9 E29598 ; # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
|
||||
AA E29599 ; # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
|
||||
AB E2959A ; # BOX DRAWINGS DOUBLE UP AND RIGHT
|
||||
AC E2959B ; # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
|
||||
AD E2959C ; # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
|
||||
AE E2959D ; # BOX DRAWINGS DOUBLE UP AND LEFT
|
||||
AF E2959E ; # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
|
||||
B0 E2959F ; # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
|
||||
B1 E295A0 ; # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
|
||||
B2 E295A1 ; # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
|
||||
B3 D081 ; # CYRILLIC CAPITAL LETTER IO
|
||||
B4 E295A2 ; # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
|
||||
B5 E295A3 ; # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
|
||||
B6 E295A4 ; # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
|
||||
B7 E295A5 ; # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
|
||||
B8 E295A6 ; # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
|
||||
B9 E295A7 ; # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
|
||||
BA E295A8 ; # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
|
||||
BB E295A9 ; # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
BC E295AA ; # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
|
||||
BD E295AB ; # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
|
||||
BE E295AC ; # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
|
||||
BF C2A9 ; # COPYRIGHT SIGN
|
||||
C0 D18E ; # CYRILLIC SMALL LETTER YU
|
||||
C1 D0B0 ; # CYRILLIC SMALL LETTER A
|
||||
C2 D0B1 ; # CYRILLIC SMALL LETTER BE
|
||||
C3 D186 ; # CYRILLIC SMALL LETTER TSE
|
||||
C4 D0B4 ; # CYRILLIC SMALL LETTER DE
|
||||
C5 D0B5 ; # CYRILLIC SMALL LETTER IE
|
||||
C6 D184 ; # CYRILLIC SMALL LETTER EF
|
||||
C7 D0B3 ; # CYRILLIC SMALL LETTER GHE
|
||||
C8 D185 ; # CYRILLIC SMALL LETTER HA
|
||||
C9 D0B8 ; # CYRILLIC SMALL LETTER I
|
||||
CA D0B9 ; # CYRILLIC SMALL LETTER SHORT I
|
||||
CB D0BA ; # CYRILLIC SMALL LETTER KA
|
||||
CC D0BB ; # CYRILLIC SMALL LETTER EL
|
||||
CD D0BC ; # CYRILLIC SMALL LETTER EM
|
||||
CE D0BD ; # CYRILLIC SMALL LETTER EN
|
||||
CF D0BE ; # CYRILLIC SMALL LETTER O
|
||||
D0 D0BF ; # CYRILLIC SMALL LETTER PE
|
||||
D1 D18F ; # CYRILLIC SMALL LETTER YA
|
||||
D2 D180 ; # CYRILLIC SMALL LETTER ER
|
||||
D3 D181 ; # CYRILLIC SMALL LETTER ES
|
||||
D4 D182 ; # CYRILLIC SMALL LETTER TE
|
||||
D5 D183 ; # CYRILLIC SMALL LETTER U
|
||||
D6 D0B6 ; # CYRILLIC SMALL LETTER ZHE
|
||||
D7 D0B2 ; # CYRILLIC SMALL LETTER VE
|
||||
D8 D18C ; # CYRILLIC SMALL LETTER SOFT SIGN
|
||||
D9 D18B ; # CYRILLIC SMALL LETTER YERU
|
||||
DA D0B7 ; # CYRILLIC SMALL LETTER ZE
|
||||
DB D188 ; # CYRILLIC SMALL LETTER SHA
|
||||
DC D18D ; # CYRILLIC SMALL LETTER E
|
||||
DD D189 ; # CYRILLIC SMALL LETTER SHCHA
|
||||
DE D187 ; # CYRILLIC SMALL LETTER CHE
|
||||
DF D18A ; # CYRILLIC SMALL LETTER HARD SIGN
|
||||
E0 D0AE ; # CYRILLIC CAPITAL LETTER YU
|
||||
E1 D090 ; # CYRILLIC CAPITAL LETTER A
|
||||
E2 D091 ; # CYRILLIC CAPITAL LETTER BE
|
||||
E3 D0A6 ; # CYRILLIC CAPITAL LETTER TSE
|
||||
E4 D094 ; # CYRILLIC CAPITAL LETTER DE
|
||||
E5 D095 ; # CYRILLIC CAPITAL LETTER IE
|
||||
E6 D0A4 ; # CYRILLIC CAPITAL LETTER EF
|
||||
E7 D093 ; # CYRILLIC CAPITAL LETTER GHE
|
||||
E8 D0A5 ; # CYRILLIC CAPITAL LETTER HA
|
||||
E9 D098 ; # CYRILLIC CAPITAL LETTER I
|
||||
EA D099 ; # CYRILLIC CAPITAL LETTER SHORT I
|
||||
EB D09A ; # CYRILLIC CAPITAL LETTER KA
|
||||
EC D09B ; # CYRILLIC CAPITAL LETTER EL
|
||||
ED D09C ; # CYRILLIC CAPITAL LETTER EM
|
||||
EE D09D ; # CYRILLIC CAPITAL LETTER EN
|
||||
EF D09E ; # CYRILLIC CAPITAL LETTER O
|
||||
F0 D09F ; # CYRILLIC CAPITAL LETTER PE
|
||||
F1 D0AF ; # CYRILLIC CAPITAL LETTER YA
|
||||
F2 D0A0 ; # CYRILLIC CAPITAL LETTER ER
|
||||
F3 D0A1 ; # CYRILLIC CAPITAL LETTER ES
|
||||
F4 D0A2 ; # CYRILLIC CAPITAL LETTER TE
|
||||
F5 D0A3 ; # CYRILLIC CAPITAL LETTER U
|
||||
F6 D096 ; # CYRILLIC CAPITAL LETTER ZHE
|
||||
F7 D092 ; # CYRILLIC CAPITAL LETTER VE
|
||||
F8 D0AC ; # CYRILLIC CAPITAL LETTER SOFT SIGN
|
||||
F9 D0AB ; # CYRILLIC CAPITAL LETTER YERU
|
||||
FA D097 ; # CYRILLIC CAPITAL LETTER ZE
|
||||
FB D0A8 ; # CYRILLIC CAPITAL LETTER SHA
|
||||
FC D0AD ; # CYRILLIC CAPITAL LETTER E
|
||||
FD D0A9 ; # CYRILLIC CAPITAL LETTER SHCHA
|
||||
FE D0A7 ; # CYRILLIC CAPITAL LETTER CHE
|
||||
FF D0AA ; # CYRILLIC CAPITAL LETTER HARD SIGN
|
||||
}
|
48
nginx-1.20.2/contrib/unicode2nginx/unicode-to-nginx.pl
Normal file
48
nginx-1.20.2/contrib/unicode2nginx/unicode-to-nginx.pl
Normal file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# Convert unicode mappings to nginx configuration file format.
|
||||
|
||||
# You may find useful mappings in various places, including
|
||||
# unicode.org official site:
|
||||
#
|
||||
# http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT
|
||||
# http://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT
|
||||
|
||||
# Needs perl 5.6 or later.
|
||||
|
||||
# Written by Maxim Dounin, mdounin@mdounin.ru
|
||||
|
||||
###############################################################################
|
||||
|
||||
require 5.006;
|
||||
|
||||
while (<>) {
|
||||
# Skip comments and empty lines
|
||||
|
||||
next if /^#/;
|
||||
next if /^\s*$/;
|
||||
chomp;
|
||||
|
||||
# Convert mappings
|
||||
|
||||
if (/^\s*0x(..)\s*0x(....)\s*(#.*)/) {
|
||||
# Mapping <from-code> <unicode-code> "#" <unicode-name>
|
||||
my $cs_code = $1;
|
||||
my $un_code = $2;
|
||||
my $un_name = $3;
|
||||
|
||||
# Produce UTF-8 sequence from character code;
|
||||
|
||||
my $un_utf8 = join('',
|
||||
map { sprintf("%02X", $_) }
|
||||
unpack("U0C*", pack("U", hex($un_code)))
|
||||
);
|
||||
|
||||
print " $cs_code $un_utf8 ; $un_name\n";
|
||||
|
||||
} else {
|
||||
warn "Unrecognized line: '$_'";
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
130
nginx-1.20.2/contrib/unicode2nginx/win-utf
Normal file
130
nginx-1.20.2/contrib/unicode2nginx/win-utf
Normal file
@ -0,0 +1,130 @@
|
||||
charset_map windows-1251 utf-8 {
|
||||
|
||||
80 D082 ; #CYRILLIC CAPITAL LETTER DJE
|
||||
81 D083 ; #CYRILLIC CAPITAL LETTER GJE
|
||||
82 E2809A ; #SINGLE LOW-9 QUOTATION MARK
|
||||
83 D193 ; #CYRILLIC SMALL LETTER GJE
|
||||
84 E2809E ; #DOUBLE LOW-9 QUOTATION MARK
|
||||
85 E280A6 ; #HORIZONTAL ELLIPSIS
|
||||
86 E280A0 ; #DAGGER
|
||||
87 E280A1 ; #DOUBLE DAGGER
|
||||
88 E282AC ; #EURO SIGN
|
||||
89 E280B0 ; #PER MILLE SIGN
|
||||
8A D089 ; #CYRILLIC CAPITAL LETTER LJE
|
||||
8B E280B9 ; #SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
8C D08A ; #CYRILLIC CAPITAL LETTER NJE
|
||||
8D D08C ; #CYRILLIC CAPITAL LETTER KJE
|
||||
8E D08B ; #CYRILLIC CAPITAL LETTER TSHE
|
||||
8F D08F ; #CYRILLIC CAPITAL LETTER DZHE
|
||||
90 D192 ; #CYRILLIC SMALL LETTER DJE
|
||||
91 E28098 ; #LEFT SINGLE QUOTATION MARK
|
||||
92 E28099 ; #RIGHT SINGLE QUOTATION MARK
|
||||
93 E2809C ; #LEFT DOUBLE QUOTATION MARK
|
||||
94 E2809D ; #RIGHT DOUBLE QUOTATION MARK
|
||||
95 E280A2 ; #BULLET
|
||||
96 E28093 ; #EN DASH
|
||||
97 E28094 ; #EM DASH
|
||||
99 E284A2 ; #TRADE MARK SIGN
|
||||
9A D199 ; #CYRILLIC SMALL LETTER LJE
|
||||
9B E280BA ; #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
9C D19A ; #CYRILLIC SMALL LETTER NJE
|
||||
9D D19C ; #CYRILLIC SMALL LETTER KJE
|
||||
9E D19B ; #CYRILLIC SMALL LETTER TSHE
|
||||
9F D19F ; #CYRILLIC SMALL LETTER DZHE
|
||||
A0 C2A0 ; #NO-BREAK SPACE
|
||||
A1 D08E ; #CYRILLIC CAPITAL LETTER SHORT U
|
||||
A2 D19E ; #CYRILLIC SMALL LETTER SHORT U
|
||||
A3 D088 ; #CYRILLIC CAPITAL LETTER JE
|
||||
A4 C2A4 ; #CURRENCY SIGN
|
||||
A5 D290 ; #CYRILLIC CAPITAL LETTER GHE WITH UPTURN
|
||||
A6 C2A6 ; #BROKEN BAR
|
||||
A7 C2A7 ; #SECTION SIGN
|
||||
A8 D081 ; #CYRILLIC CAPITAL LETTER IO
|
||||
A9 C2A9 ; #COPYRIGHT SIGN
|
||||
AA D084 ; #CYRILLIC CAPITAL LETTER UKRAINIAN IE
|
||||
AB C2AB ; #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
AC C2AC ; #NOT SIGN
|
||||
AD C2AD ; #SOFT HYPHEN
|
||||
AE C2AE ; #REGISTERED SIGN
|
||||
AF D087 ; #CYRILLIC CAPITAL LETTER YI
|
||||
B0 C2B0 ; #DEGREE SIGN
|
||||
B1 C2B1 ; #PLUS-MINUS SIGN
|
||||
B2 D086 ; #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
|
||||
B3 D196 ; #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
|
||||
B4 D291 ; #CYRILLIC SMALL LETTER GHE WITH UPTURN
|
||||
B5 C2B5 ; #MICRO SIGN
|
||||
B6 C2B6 ; #PILCROW SIGN
|
||||
B7 C2B7 ; #MIDDLE DOT
|
||||
B8 D191 ; #CYRILLIC SMALL LETTER IO
|
||||
B9 E28496 ; #NUMERO SIGN
|
||||
BA D194 ; #CYRILLIC SMALL LETTER UKRAINIAN IE
|
||||
BB C2BB ; #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
BC D198 ; #CYRILLIC SMALL LETTER JE
|
||||
BD D085 ; #CYRILLIC CAPITAL LETTER DZE
|
||||
BE D195 ; #CYRILLIC SMALL LETTER DZE
|
||||
BF D197 ; #CYRILLIC SMALL LETTER YI
|
||||
C0 D090 ; #CYRILLIC CAPITAL LETTER A
|
||||
C1 D091 ; #CYRILLIC CAPITAL LETTER BE
|
||||
C2 D092 ; #CYRILLIC CAPITAL LETTER VE
|
||||
C3 D093 ; #CYRILLIC CAPITAL LETTER GHE
|
||||
C4 D094 ; #CYRILLIC CAPITAL LETTER DE
|
||||
C5 D095 ; #CYRILLIC CAPITAL LETTER IE
|
||||
C6 D096 ; #CYRILLIC CAPITAL LETTER ZHE
|
||||
C7 D097 ; #CYRILLIC CAPITAL LETTER ZE
|
||||
C8 D098 ; #CYRILLIC CAPITAL LETTER I
|
||||
C9 D099 ; #CYRILLIC CAPITAL LETTER SHORT I
|
||||
CA D09A ; #CYRILLIC CAPITAL LETTER KA
|
||||
CB D09B ; #CYRILLIC CAPITAL LETTER EL
|
||||
CC D09C ; #CYRILLIC CAPITAL LETTER EM
|
||||
CD D09D ; #CYRILLIC CAPITAL LETTER EN
|
||||
CE D09E ; #CYRILLIC CAPITAL LETTER O
|
||||
CF D09F ; #CYRILLIC CAPITAL LETTER PE
|
||||
D0 D0A0 ; #CYRILLIC CAPITAL LETTER ER
|
||||
D1 D0A1 ; #CYRILLIC CAPITAL LETTER ES
|
||||
D2 D0A2 ; #CYRILLIC CAPITAL LETTER TE
|
||||
D3 D0A3 ; #CYRILLIC CAPITAL LETTER U
|
||||
D4 D0A4 ; #CYRILLIC CAPITAL LETTER EF
|
||||
D5 D0A5 ; #CYRILLIC CAPITAL LETTER HA
|
||||
D6 D0A6 ; #CYRILLIC CAPITAL LETTER TSE
|
||||
D7 D0A7 ; #CYRILLIC CAPITAL LETTER CHE
|
||||
D8 D0A8 ; #CYRILLIC CAPITAL LETTER SHA
|
||||
D9 D0A9 ; #CYRILLIC CAPITAL LETTER SHCHA
|
||||
DA D0AA ; #CYRILLIC CAPITAL LETTER HARD SIGN
|
||||
DB D0AB ; #CYRILLIC CAPITAL LETTER YERU
|
||||
DC D0AC ; #CYRILLIC CAPITAL LETTER SOFT SIGN
|
||||
DD D0AD ; #CYRILLIC CAPITAL LETTER E
|
||||
DE D0AE ; #CYRILLIC CAPITAL LETTER YU
|
||||
DF D0AF ; #CYRILLIC CAPITAL LETTER YA
|
||||
E0 D0B0 ; #CYRILLIC SMALL LETTER A
|
||||
E1 D0B1 ; #CYRILLIC SMALL LETTER BE
|
||||
E2 D0B2 ; #CYRILLIC SMALL LETTER VE
|
||||
E3 D0B3 ; #CYRILLIC SMALL LETTER GHE
|
||||
E4 D0B4 ; #CYRILLIC SMALL LETTER DE
|
||||
E5 D0B5 ; #CYRILLIC SMALL LETTER IE
|
||||
E6 D0B6 ; #CYRILLIC SMALL LETTER ZHE
|
||||
E7 D0B7 ; #CYRILLIC SMALL LETTER ZE
|
||||
E8 D0B8 ; #CYRILLIC SMALL LETTER I
|
||||
E9 D0B9 ; #CYRILLIC SMALL LETTER SHORT I
|
||||
EA D0BA ; #CYRILLIC SMALL LETTER KA
|
||||
EB D0BB ; #CYRILLIC SMALL LETTER EL
|
||||
EC D0BC ; #CYRILLIC SMALL LETTER EM
|
||||
ED D0BD ; #CYRILLIC SMALL LETTER EN
|
||||
EE D0BE ; #CYRILLIC SMALL LETTER O
|
||||
EF D0BF ; #CYRILLIC SMALL LETTER PE
|
||||
F0 D180 ; #CYRILLIC SMALL LETTER ER
|
||||
F1 D181 ; #CYRILLIC SMALL LETTER ES
|
||||
F2 D182 ; #CYRILLIC SMALL LETTER TE
|
||||
F3 D183 ; #CYRILLIC SMALL LETTER U
|
||||
F4 D184 ; #CYRILLIC SMALL LETTER EF
|
||||
F5 D185 ; #CYRILLIC SMALL LETTER HA
|
||||
F6 D186 ; #CYRILLIC SMALL LETTER TSE
|
||||
F7 D187 ; #CYRILLIC SMALL LETTER CHE
|
||||
F8 D188 ; #CYRILLIC SMALL LETTER SHA
|
||||
F9 D189 ; #CYRILLIC SMALL LETTER SHCHA
|
||||
FA D18A ; #CYRILLIC SMALL LETTER HARD SIGN
|
||||
FB D18B ; #CYRILLIC SMALL LETTER YERU
|
||||
FC D18C ; #CYRILLIC SMALL LETTER SOFT SIGN
|
||||
FD D18D ; #CYRILLIC SMALL LETTER E
|
||||
FE D18E ; #CYRILLIC SMALL LETTER YU
|
||||
FF D18F ; #CYRILLIC SMALL LETTER YA
|
||||
}
|
4
nginx-1.20.2/contrib/vim/ftdetect/nginx.vim
Normal file
4
nginx-1.20.2/contrib/vim/ftdetect/nginx.vim
Normal file
@ -0,0 +1,4 @@
|
||||
au BufRead,BufNewFile *.nginx set ft=nginx
|
||||
au BufRead,BufNewFile */etc/nginx/* set ft=nginx
|
||||
au BufRead,BufNewFile */usr/local/nginx/conf/* set ft=nginx
|
||||
au BufRead,BufNewFile nginx.conf set ft=nginx
|
1
nginx-1.20.2/contrib/vim/ftplugin/nginx.vim
Normal file
1
nginx-1.20.2/contrib/vim/ftplugin/nginx.vim
Normal file
@ -0,0 +1 @@
|
||||
setlocal commentstring=#\ %s
|
11
nginx-1.20.2/contrib/vim/indent/nginx.vim
Normal file
11
nginx-1.20.2/contrib/vim/indent/nginx.vim
Normal file
@ -0,0 +1,11 @@
|
||||
if exists("b:did_indent")
|
||||
finish
|
||||
endif
|
||||
let b:did_indent = 1
|
||||
|
||||
setlocal indentexpr=
|
||||
|
||||
" cindent actually works for nginx' simple file structure
|
||||
setlocal cindent
|
||||
" Just make sure that the comments are not reset as defs would be.
|
||||
setlocal cinkeys-=0#
|
2439
nginx-1.20.2/contrib/vim/syntax/nginx.vim
Normal file
2439
nginx-1.20.2/contrib/vim/syntax/nginx.vim
Normal file
File diff suppressed because it is too large
Load Diff
8765
nginx-1.20.2/docs/CHANGES
Normal file
8765
nginx-1.20.2/docs/CHANGES
Normal file
File diff suppressed because it is too large
Load Diff
8915
nginx-1.20.2/docs/CHANGES.ru
Normal file
8915
nginx-1.20.2/docs/CHANGES.ru
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user