收银后台上传!
This commit is contained in:
parent
3953b18554
commit
24bcc09bc2
|
|
@ -0,0 +1,7 @@
|
|||
### IDEA ###
|
||||
.idea/*
|
||||
*.iml
|
||||
*/target/*
|
||||
*/*.iml
|
||||
/.gradle/
|
||||
/application.pid
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
### IDEA ###
|
||||
.idea/*
|
||||
*.iml
|
||||
*/target/*
|
||||
*/*.iml
|
||||
/.gradle/
|
||||
/application.pid
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
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:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
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
|
||||
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
|
||||
|
||||
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 2019-2020 Zheng Jie
|
||||
|
||||
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.
|
||||
123
README.md
123
README.md
|
|
@ -1,39 +1,108 @@
|
|||
# cashierAdmin
|
||||
<h1 style="text-align: center">ELADMIN 后台管理系统</h1>
|
||||
<div style="text-align: center">
|
||||
|
||||
#### 介绍
|
||||
{**以下是 Gitee 平台说明,您可以替换此简介**
|
||||
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
|
||||
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
|
||||
[](https://github.com/elunez/eladmin/blob/master/LICENSE)
|
||||
[](https://gitee.com/elunez/eladmin)
|
||||
[](https://github.com/elunez/eladmin)
|
||||
[](https://github.com/elunez/eladmin)
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
</div>
|
||||
|
||||
#### 项目简介
|
||||
一个基于 Spring Boot 2.1.0 、 Spring Boot Jpa、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统
|
||||
|
||||
#### 安装教程
|
||||
**开发文档:** [https://eladmin.vip](https://eladmin.vip)
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
**体验地址:** [https://eladmin.vip/demo](https://eladmin.vip/demo)
|
||||
|
||||
#### 使用说明
|
||||
**账号密码:** `admin / 123456`
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
#### 项目源码
|
||||
|
||||
#### 参与贡献
|
||||
| | 后端源码 | 前端源码 |
|
||||
|--- |--- | --- |
|
||||
| github | https://github.com/elunez/eladmin | https://github.com/elunez/eladmin-web |
|
||||
| 码云 | https://gitee.com/elunez/eladmin | https://gitee.com/elunez/eladmin-web |
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
#### 主要特性
|
||||
- 使用最新技术栈,社区资源丰富。
|
||||
- 高效率开发,代码生成器可一键生成前后端代码
|
||||
- 支持数据字典,可方便地对一些状态进行管理
|
||||
- 支持接口限流,避免恶意请求导致服务层压力过大
|
||||
- 支持接口级别的功能权限与数据权限,可自定义操作
|
||||
- 自定义权限注解与匿名接口注解,可快速对接口拦截与放行
|
||||
- 对一些常用地前端组件封装:表格数据请求、数据字典等
|
||||
- 前后端统一异常拦截处理,统一输出异常,避免繁琐的判断
|
||||
- 支持在线用户管理与服务器性能监控,支持限制单用户登录
|
||||
- 支持运维管理,可方便地对远程服务器的应用进行部署与管理
|
||||
|
||||
#### 系统功能
|
||||
- 用户管理:提供用户的相关配置,新增用户后,默认密码为123456
|
||||
- 角色管理:对权限与菜单进行分配,可根据部门设置角色的数据权限
|
||||
- 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单
|
||||
- 部门管理:可配置系统组织架构,树形表格展示
|
||||
- 岗位管理:配置各个部门的职位
|
||||
- 字典管理:可维护常用一些固定的数据,如:状态,性别等
|
||||
- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错
|
||||
- SQL监控:采用druid 监控数据库访问性能,默认用户名admin,密码123456
|
||||
- 定时任务:整合Quartz做定时任务,加入任务日志,任务运行情况一目了然
|
||||
- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
|
||||
- 邮件工具:配合富文本,发送html格式的邮件
|
||||
- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
|
||||
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
|
||||
- 服务监控:监控服务器的负载情况
|
||||
- 运维管理:一键部署你的应用
|
||||
|
||||
#### 特技
|
||||
#### 项目结构
|
||||
项目采用按功能分模块的开发方式,结构如下
|
||||
|
||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
|
||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
- `eladmin-common` 为系统的公共模块,各种工具类,公共配置存在该模块
|
||||
|
||||
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
|
||||
|
||||
- `eladmin-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块
|
||||
|
||||
- `eladmin-tools` 为第三方工具模块,包含:图床、邮件、云存储、本地存储、支付宝
|
||||
|
||||
- `eladmin-generator` 为系统的代码生成模块,代码生成的模板在 system 模块中
|
||||
|
||||
#### 详细结构
|
||||
|
||||
```
|
||||
- eladmin-common 公共模块
|
||||
- annotation 为系统自定义注解
|
||||
- aspect 自定义注解的切面
|
||||
- base 提供了Entity、DTO基类和mapstruct的通用mapper
|
||||
- config 自定义权限实现、redis配置、swagger配置、Rsa配置等
|
||||
- exception 项目统一异常的处理
|
||||
- utils 系统通用工具类
|
||||
- eladmin-system 系统核心模块(系统启动入口)
|
||||
- config 配置跨域与静态资源,与数据权限
|
||||
- thread 线程池相关
|
||||
- modules 系统相关模块(登录授权、系统监控、定时任务、运维管理等)
|
||||
- eladmin-logging 系统日志模块
|
||||
- eladmin-tools 系统第三方工具模块
|
||||
- eladmin-generator 系统代码生成模块
|
||||
```
|
||||
|
||||
#### 特别鸣谢
|
||||
|
||||
- 感谢 [七牛云](https://portal.qiniu.com/signup?utm_source=kaiyuan&utm_media=ELADMIN) 提供的免费云存储与CDN加速支持
|
||||
|
||||
- 感谢 [JetBrains](https://www.jetbrains.com/) 提供的非商业开源软件开发授权
|
||||
|
||||
- 感谢 [PanJiaChen](https://github.com/PanJiaChen/vue-element-admin) 大佬提供的前端模板
|
||||
|
||||
- 感谢 [Moxun](https://github.com/moxun1639) 大佬提供的前端 Curd 通用组件
|
||||
|
||||
- 感谢 [zhy6599](https://gitee.com/zhy6599) 大佬提供的后端运维管理相关功能
|
||||
|
||||
- 感谢 [j.yao.SUSE](https://github.com/everhopingandwaiting) 大佬提供的匿名接口与Redis限流等功能
|
||||
|
||||
- 感谢 [d15801543974](https://github.com/d15801543974) 大佬提供的基于注解的通用查询方式
|
||||
|
||||
#### 项目捐赠
|
||||
项目的发展离不开你的支持,请作者喝杯咖啡吧☕ [Donate](https://eladmin.vip/donation/)
|
||||
|
||||
#### 反馈交流
|
||||
- QQ交流群:一群:<strike>891137268</strike> 、二群:<strike>947578238</strike>、三群:659622532
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?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>eladmin</artifactId>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<version>2.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<properties>
|
||||
<hutool.version>5.7.22</hutool.version>
|
||||
</properties>
|
||||
|
||||
<artifactId>eladmin-common</artifactId>
|
||||
<name>公共模块</name>
|
||||
|
||||
<dependencies>
|
||||
<!--工具包-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author jacky
|
||||
* 用于标记匿名访问方法
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnonymousAccess {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用于判断是否过滤数据权限
|
||||
* 1、如果没有用到 @OneToOne 这种关联关系,只需要填写 fieldName [参考:DeptQueryCriteria.class]
|
||||
* 2、如果用到了 @OneToOne ,fieldName 和 joinName 都需要填写,拿UserQueryCriteria.class举例:
|
||||
* 应该是 @DataPermission(joinName = "dept", fieldName = "id")
|
||||
* </p>
|
||||
* @author Zheng Jie
|
||||
* @website https://eladmin.vip
|
||||
* @date 2020-05-07
|
||||
**/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DataPermission {
|
||||
|
||||
/**
|
||||
* Entity 中的字段名称
|
||||
*/
|
||||
String fieldName() default "";
|
||||
|
||||
/**
|
||||
* Entity 中与部门关联的字段名称
|
||||
*/
|
||||
String joinName() default "";
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.annotation;
|
||||
|
||||
import me.zhengjie.aspect.LimitType;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author jacky
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Limit {
|
||||
|
||||
// 资源名称,用于描述接口功能
|
||||
String name() default "";
|
||||
|
||||
// 资源 key
|
||||
String key() default "";
|
||||
|
||||
// key prefix
|
||||
String prefix() default "";
|
||||
|
||||
// 时间的,单位秒
|
||||
int period();
|
||||
|
||||
// 限制访问次数
|
||||
int count();
|
||||
|
||||
// 限制类型
|
||||
LimitType limitType() default LimitType.CUSTOMER;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-6-4 13:52:30
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Query {
|
||||
|
||||
// Dong ZhaoYang 2017/8/7 基本对象的属性名
|
||||
String propName() default "";
|
||||
// Dong ZhaoYang 2017/8/7 查询方式
|
||||
Type type() default Type.EQUAL;
|
||||
|
||||
/**
|
||||
* 连接查询的属性名,如User类中的dept
|
||||
*/
|
||||
String joinName() default "";
|
||||
|
||||
/**
|
||||
* 默认左连接
|
||||
*/
|
||||
Join join() default Join.LEFT;
|
||||
|
||||
/**
|
||||
* 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username")
|
||||
*/
|
||||
String blurry() default "";
|
||||
|
||||
enum Type {
|
||||
// jie 2019/6/4 相等
|
||||
EQUAL
|
||||
// Dong ZhaoYang 2017/8/7 大于等于
|
||||
, GREATER_THAN
|
||||
// Dong ZhaoYang 2017/8/7 小于等于
|
||||
, LESS_THAN
|
||||
// Dong ZhaoYang 2017/8/7 中模糊查询
|
||||
, INNER_LIKE
|
||||
// Dong ZhaoYang 2017/8/7 左模糊查询
|
||||
, LEFT_LIKE
|
||||
// Dong ZhaoYang 2017/8/7 右模糊查询
|
||||
, RIGHT_LIKE
|
||||
// Dong ZhaoYang 2017/8/7 小于
|
||||
, LESS_THAN_NQ
|
||||
// jie 2019/6/4 包含
|
||||
, IN
|
||||
// 不包含
|
||||
, NOT_IN
|
||||
// 不等于
|
||||
,NOT_EQUAL
|
||||
// between
|
||||
,BETWEEN
|
||||
// 不为空
|
||||
,NOT_NULL
|
||||
// 为空
|
||||
,IS_NULL
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询
|
||||
*/
|
||||
enum Join {
|
||||
/** jie 2019-6-4 13:18:30 */
|
||||
LEFT, RIGHT, INNER
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package me.zhengjie.annotation.rest;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Annotation for mapping HTTP {@code DELETE} requests onto specific handler
|
||||
* methods.
|
||||
* 支持匿名访问 DeleteMapping
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @see AnonymousGetMapping
|
||||
* @see AnonymousPostMapping
|
||||
* @see AnonymousPutMapping
|
||||
* @see AnonymousPatchMapping
|
||||
* @see RequestMapping
|
||||
*/
|
||||
@AnonymousAccess
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@RequestMapping(method = RequestMethod.DELETE)
|
||||
public @interface AnonymousDeleteMapping {
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#name}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#value}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#path}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] path() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#params}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] params() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#headers}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] headers() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#consumes}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] consumes() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#produces}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] produces() default {};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package me.zhengjie.annotation.rest;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Annotation for mapping HTTP {@code GET} requests onto specific handler
|
||||
* methods.
|
||||
* <p>
|
||||
* 支持匿名访问 GetMapping
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @see RequestMapping
|
||||
*/
|
||||
@AnonymousAccess
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public @interface AnonymousGetMapping {
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#name}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#value}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#path}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] path() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#params}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] params() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#headers}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] headers() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#consumes}.
|
||||
*
|
||||
* @since 4.3.5
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] consumes() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#produces}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] produces() default {};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package me.zhengjie.annotation.rest;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Annotation for mapping HTTP {@code PATCH} requests onto specific handler
|
||||
* methods.
|
||||
* * 支持匿名访问 PatchMapping
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @see AnonymousGetMapping
|
||||
* @see AnonymousPostMapping
|
||||
* @see AnonymousPutMapping
|
||||
* @see AnonymousDeleteMapping
|
||||
* @see RequestMapping
|
||||
*/
|
||||
@AnonymousAccess
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@RequestMapping(method = RequestMethod.PATCH)
|
||||
public @interface AnonymousPatchMapping {
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#name}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#value}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#path}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] path() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#params}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] params() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#headers}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] headers() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#consumes}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] consumes() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#produces}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] produces() default {};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package me.zhengjie.annotation.rest;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Annotation for mapping HTTP {@code POST} requests onto specific handler
|
||||
* methods.
|
||||
* 支持匿名访问 PostMapping
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @see AnonymousGetMapping
|
||||
* @see AnonymousPostMapping
|
||||
* @see AnonymousPutMapping
|
||||
* @see AnonymousDeleteMapping
|
||||
* @see RequestMapping
|
||||
*/
|
||||
@AnonymousAccess
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public @interface AnonymousPostMapping {
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#name}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#value}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#path}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] path() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#params}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] params() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#headers}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] headers() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#consumes}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] consumes() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#produces}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] produces() default {};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package me.zhengjie.annotation.rest;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Annotation for mapping HTTP {@code PUT} requests onto specific handler
|
||||
* methods.
|
||||
* * 支持匿名访问 PutMapping
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @see AnonymousGetMapping
|
||||
* @see AnonymousPostMapping
|
||||
* @see AnonymousPutMapping
|
||||
* @see AnonymousDeleteMapping
|
||||
* @see RequestMapping
|
||||
*/
|
||||
@AnonymousAccess
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@RequestMapping(method = RequestMethod.PUT)
|
||||
public @interface AnonymousPutMapping {
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#name}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#value}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#path}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] path() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#params}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] params() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#headers}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] headers() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#consumes}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] consumes() default {};
|
||||
|
||||
/**
|
||||
* Alias for {@link RequestMapping#produces}.
|
||||
*/
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] produces() default {};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.aspect;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.zhengjie.annotation.Limit;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.utils.RequestHolder;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class LimitAspect {
|
||||
|
||||
private final RedisTemplate<Object,Object> redisTemplate;
|
||||
private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class);
|
||||
|
||||
public LimitAspect(RedisTemplate<Object,Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Pointcut("@annotation(me.zhengjie.annotation.Limit)")
|
||||
public void pointcut() {
|
||||
}
|
||||
|
||||
@Around("pointcut()")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method signatureMethod = signature.getMethod();
|
||||
Limit limit = signatureMethod.getAnnotation(Limit.class);
|
||||
LimitType limitType = limit.limitType();
|
||||
String key = limit.key();
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
if (limitType == LimitType.IP) {
|
||||
key = StringUtils.getIp(request);
|
||||
} else {
|
||||
key = signatureMethod.getName();
|
||||
}
|
||||
}
|
||||
|
||||
ImmutableList<Object> keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replace("/","_")));
|
||||
|
||||
String luaScript = buildLuaScript();
|
||||
RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);
|
||||
Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period());
|
||||
if (null != count && count.intValue() <= limit.count()) {
|
||||
logger.info("第{}次访问key为 {},描述为 [{}] 的接口", count, keys, limit.name());
|
||||
return joinPoint.proceed();
|
||||
} else {
|
||||
throw new BadRequestException("访问次数受限制");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流脚本
|
||||
*/
|
||||
private String buildLuaScript() {
|
||||
return "local c" +
|
||||
"\nc = redis.call('get',KEYS[1])" +
|
||||
"\nif c and tonumber(c) > tonumber(ARGV[1]) then" +
|
||||
"\nreturn c;" +
|
||||
"\nend" +
|
||||
"\nc = redis.call('incr',KEYS[1])" +
|
||||
"\nif tonumber(c) == 1 then" +
|
||||
"\nredis.call('expire',KEYS[1],ARGV[2])" +
|
||||
"\nend" +
|
||||
"\nreturn c;";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.aspect;
|
||||
|
||||
/**
|
||||
* 限流枚举
|
||||
* @author /
|
||||
*/
|
||||
public enum LimitType {
|
||||
// 默认
|
||||
CUSTOMER,
|
||||
// by ip addr
|
||||
IP
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package me.zhengjie.base;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019年10月24日20:48:53
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BaseDTO implements Serializable {
|
||||
|
||||
private String createBy;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
private Timestamp createTime;
|
||||
|
||||
private Timestamp updateTime;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder builder = new ToStringBuilder(this);
|
||||
Field[] fields = this.getClass().getDeclaredFields();
|
||||
try {
|
||||
for (Field f : fields) {
|
||||
f.setAccessible(true);
|
||||
builder.append(f.getName(), f.get(this)).append("\n");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
builder.append("toString builder encounter an error");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.base;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EntityListeners;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* 通用字段, is_del 根据需求自行添加
|
||||
* @author Zheng Jie
|
||||
* @Date 2019年10月24日20:46:32
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@MappedSuperclass
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public class BaseEntity implements Serializable {
|
||||
|
||||
@CreatedBy
|
||||
@Column(name = "create_by", updatable = false)
|
||||
@ApiModelProperty(value = "创建人", hidden = true)
|
||||
private String createBy;
|
||||
|
||||
@LastModifiedBy
|
||||
@Column(name = "update_by")
|
||||
@ApiModelProperty(value = "更新人", hidden = true)
|
||||
private String updateBy;
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(name = "create_time", updatable = false)
|
||||
@ApiModelProperty(value = "创建时间", hidden = true)
|
||||
private Timestamp createTime;
|
||||
|
||||
@UpdateTimestamp
|
||||
@Column(name = "update_time")
|
||||
@ApiModelProperty(value = "更新时间", hidden = true)
|
||||
private Timestamp updateTime;
|
||||
|
||||
/* 分组校验 */
|
||||
public @interface Create {}
|
||||
|
||||
/* 分组校验 */
|
||||
public @interface Update {}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder builder = new ToStringBuilder(this);
|
||||
Field[] fields = this.getClass().getDeclaredFields();
|
||||
try {
|
||||
for (Field f : fields) {
|
||||
f.setAccessible(true);
|
||||
builder.append(f.getName(), f.get(this)).append("\n");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
builder.append("toString builder encounter an error");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.base;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public interface BaseMapper<D, E> {
|
||||
|
||||
/**
|
||||
* DTO转Entity
|
||||
* @param dto /
|
||||
* @return /
|
||||
*/
|
||||
E toEntity(D dto);
|
||||
|
||||
/**
|
||||
* Entity转DTO
|
||||
* @param entity /
|
||||
* @return /
|
||||
*/
|
||||
D toDto(E entity);
|
||||
|
||||
/**
|
||||
* DTO集合转Entity集合
|
||||
* @param dtoList /
|
||||
* @return /
|
||||
*/
|
||||
List <E> toEntity(List<D> dtoList);
|
||||
|
||||
/**
|
||||
* Entity集合转DTO集合
|
||||
* @param entityList /
|
||||
* @return /
|
||||
*/
|
||||
List <D> toDto(List<E> entityList);
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @description : 设置审计
|
||||
* @author : Dong ZhaoYang
|
||||
* @date : 2019/10/28
|
||||
*/
|
||||
@Component("auditorAware")
|
||||
public class AuditorConfig implements AuditorAware<String> {
|
||||
|
||||
/**
|
||||
* 返回操作员标志信息
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getCurrentAuditor() {
|
||||
try {
|
||||
// 这里应根据实际业务情况获取具体信息
|
||||
return Optional.of(SecurityUtils.getCurrentUsername());
|
||||
}catch (Exception ignored){}
|
||||
// 用户定时任务,或者无Token调用的情况
|
||||
return Optional.of("System");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import lombok.Data;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2021-11-22
|
||||
**/
|
||||
@Data
|
||||
@Component
|
||||
public class ElAdminProperties {
|
||||
|
||||
public static Boolean ipLocal;
|
||||
|
||||
@Value("${ip.local-parsing}")
|
||||
public void setIpLocal(Boolean ipLocal) {
|
||||
ElAdminProperties.ipLocal = ipLocal;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Service(value = "el")
|
||||
public class ElPermissionConfig {
|
||||
|
||||
public Boolean check(String ...permissions){
|
||||
// 获取当前用户的所有权限
|
||||
List<String> elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
|
||||
// 判断当前用户的所有权限是否包含接口上定义的权限
|
||||
return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import lombok.Data;
|
||||
import me.zhengjie.utils.ElAdminConstant;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "file")
|
||||
public class FileProperties {
|
||||
|
||||
/** 文件大小限制 */
|
||||
private Long maxSize;
|
||||
|
||||
/** 头像大小限制 */
|
||||
private Long avatarMaxSize;
|
||||
|
||||
private ElPath mac;
|
||||
|
||||
private ElPath linux;
|
||||
|
||||
private ElPath windows;
|
||||
|
||||
public ElPath getPath(){
|
||||
String os = System.getProperty("os.name");
|
||||
if(os.toLowerCase().startsWith(ElAdminConstant.WIN)) {
|
||||
return windows;
|
||||
} else if(os.toLowerCase().startsWith(ElAdminConstant.MAC)){
|
||||
return mac;
|
||||
}
|
||||
return linux;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ElPath{
|
||||
|
||||
private String path;
|
||||
|
||||
private String avatar;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import reactor.util.annotation.Nullable;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@ConditionalOnClass(RedisOperations.class)
|
||||
@EnableConfigurationProperties(RedisProperties.class)
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
/**
|
||||
* 设置 redis 数据默认过期时间,默认2小时
|
||||
* 设置@cacheable 序列化方式
|
||||
*/
|
||||
@Bean
|
||||
public RedisCacheConfiguration redisCacheConfiguration(){
|
||||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||||
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
||||
configuration = configuration.serializeValuesWith(RedisSerializationContext.
|
||||
SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2));
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Bean(name = "redisTemplate")
|
||||
@ConditionalOnMissingBean(name = "redisTemplate")
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
//序列化
|
||||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||||
// value值的序列化采用fastJsonRedisSerializer
|
||||
template.setValueSerializer(fastJsonRedisSerializer);
|
||||
template.setHashValueSerializer(fastJsonRedisSerializer);
|
||||
// fastjson 升级到 1.2.83 后需要指定序列化白名单
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.service.dto");
|
||||
// 模块内的实体类
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.mnt.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.domain");
|
||||
// 模块内的 Dto
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.mnt.service.dto");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.service.dto");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.security.service.dto");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.service.dto");
|
||||
// key的序列化采用StringRedisSerializer
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义缓存key生成策略,默认将使用该策略
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return (target, method, params) -> {
|
||||
Map<String,Object> container = new HashMap<>(8);
|
||||
Class<?> targetClassClass = target.getClass();
|
||||
// 类地址
|
||||
container.put("class",targetClassClass.toGenericString());
|
||||
// 方法名称
|
||||
container.put("methodName",method.getName());
|
||||
// 包名称
|
||||
container.put("package",targetClassClass.getPackage());
|
||||
// 参数列表
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
container.put(String.valueOf(i),params[i]);
|
||||
}
|
||||
// 转为JSON字符串
|
||||
String jsonString = JSON.toJSONString(container);
|
||||
// 做SHA256 Hash计算,得到一个SHA256摘要作为Key
|
||||
return DigestUtils.sha256Hex(jsonString);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public CacheErrorHandler errorHandler() {
|
||||
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
||||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
|
||||
return new CacheErrorHandler() {
|
||||
@Override
|
||||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
|
||||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheClearError(RuntimeException e, Cache cache) {
|
||||
log.error("Redis occur handleCacheClearError:", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Value 序列化
|
||||
*
|
||||
* @author /
|
||||
* @param <T>
|
||||
*/
|
||||
class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
|
||||
private final Class<T> clazz;
|
||||
|
||||
FastJsonRedisSerializer(Class<T> clazz) {
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(T t) {
|
||||
if (t == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(byte[] bytes) {
|
||||
if (bytes == null || bytes.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
String str = new String(bytes, StandardCharsets.UTF_8);
|
||||
return JSON.parseObject(str, clazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写序列化器
|
||||
*
|
||||
* @author /
|
||||
*/
|
||||
class StringRedisSerializer implements RedisSerializer<Object> {
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
StringRedisSerializer() {
|
||||
this(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private StringRedisSerializer(Charset charset) {
|
||||
Assert.notNull(charset, "Charset must not be null!");
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deserialize(byte[] bytes) {
|
||||
return (bytes == null ? null : new String(bytes, charset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable byte[] serialize(Object object) {
|
||||
String string = JSON.toJSONString(object);
|
||||
|
||||
if (org.apache.commons.lang3.StringUtils.isBlank(string)) {
|
||||
return null;
|
||||
}
|
||||
string = string.replace("\"", "");
|
||||
return string.getBytes(charset);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @website https://eladmin.vip
|
||||
* @description
|
||||
* @date 2020-05-18
|
||||
**/
|
||||
@Data
|
||||
@Component
|
||||
public class RsaProperties {
|
||||
|
||||
public static String privateKey;
|
||||
|
||||
@Value("${rsa.private_key}")
|
||||
public void setPrivateKey(String privateKey) {
|
||||
RsaProperties.privateKey = privateKey;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.fasterxml.classmate.TypeResolver;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.schema.AlternateTypeRule;
|
||||
import springfox.documentation.schema.AlternateTypeRuleConvention;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.ApiKey;
|
||||
import springfox.documentation.service.AuthorizationScope;
|
||||
import springfox.documentation.service.SecurityReference;
|
||||
import springfox.documentation.service.SecurityScheme;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import static springfox.documentation.schema.AlternateTypeRules.newRule;
|
||||
|
||||
/**
|
||||
* api页面 /doc.html
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Value("${jwt.header}")
|
||||
private String tokenHeader;
|
||||
|
||||
@Value("${swagger.enabled}")
|
||||
private Boolean enabled;
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public Docket createRestApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.enable(enabled)
|
||||
.pathMapping("/")
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
.paths(PathSelectors.regex("^(?!/error).*"))
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
//添加登陆认证
|
||||
.securitySchemes(securitySchemes())
|
||||
.securityContexts(securityContexts());
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.description("一个简单且易上手的 Spring boot 后台管理框架")
|
||||
.title("ELADMIN 接口文档")
|
||||
.version("2.6")
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<SecurityScheme> securitySchemes() {
|
||||
//设置请求头信息
|
||||
List<SecurityScheme> securitySchemes = new ArrayList<>();
|
||||
ApiKey apiKey = new ApiKey(tokenHeader, tokenHeader, "header");
|
||||
securitySchemes.add(apiKey);
|
||||
return securitySchemes;
|
||||
}
|
||||
|
||||
private List<SecurityContext> securityContexts() {
|
||||
//设置需要登录认证的路径
|
||||
List<SecurityContext> securityContexts = new ArrayList<>();
|
||||
// ^(?!auth).*$ 表示所有包含auth的接口不需要使用securitySchemes即不需要带token
|
||||
// ^标识开始 ()里是一子表达式 ?!/auth表示匹配不是/auth的位置,匹配上则添加请求头,注意路径已/开头 .表示任意字符 *表示前面的字符匹配多次 $标识结束
|
||||
securityContexts.add(getContextByPath());
|
||||
return securityContexts;
|
||||
}
|
||||
|
||||
private SecurityContext getContextByPath() {
|
||||
return SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.operationSelector(o->o.requestMappingPattern().matches("^(?!/auth).*$"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<SecurityReference> defaultAuth() {
|
||||
List<SecurityReference> securityReferences = new ArrayList<>();
|
||||
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
||||
authorizationScopes[0] = authorizationScope;
|
||||
securityReferences.add(new SecurityReference(tokenHeader, authorizationScopes));
|
||||
return securityReferences;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Pageable转换展示在swagger中
|
||||
*/
|
||||
@Configuration
|
||||
class SwaggerDataConfig {
|
||||
|
||||
@Bean
|
||||
public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {
|
||||
return new AlternateTypeRuleConvention() {
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlternateTypeRule> rules() {
|
||||
return CollUtil.newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ApiModel
|
||||
@Data
|
||||
private static class Page {
|
||||
@ApiModelProperty("页码 (0..N)")
|
||||
private Integer page;
|
||||
|
||||
@ApiModelProperty("每页显示的数目")
|
||||
private Integer size;
|
||||
|
||||
@ApiModelProperty("以下列格式排序标准:property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件:如:id,asc")
|
||||
private List<String> sort;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.exception;
|
||||
|
||||
/**
|
||||
* 统一关于错误配置信息 异常
|
||||
*
|
||||
* @author: liaojinlong
|
||||
* @date: 2020/6/10 18:06
|
||||
*/
|
||||
public class BadConfigurationException extends RuntimeException {
|
||||
/**
|
||||
* Constructs a new runtime exception with {@code null} as its
|
||||
* detail message. The cause is not initialized, and may subsequently be
|
||||
* initialized by a call to {@link #initCause}.
|
||||
*/
|
||||
public BadConfigurationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new runtime exception with the specified detail message.
|
||||
* The cause is not initialized, and may subsequently be initialized by a
|
||||
* call to {@link #initCause}.
|
||||
*
|
||||
* @param message the detail message. The detail message is saved for
|
||||
* later retrieval by the {@link #getMessage()} method.
|
||||
*/
|
||||
public BadConfigurationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new runtime exception with the specified detail message and
|
||||
* cause. <p>Note that the detail message associated with
|
||||
* {@code cause} is <i>not</i> automatically incorporated in
|
||||
* this runtime exception's detail message.
|
||||
*
|
||||
* @param message the detail message (which is saved for later retrieval
|
||||
* by the {@link #getMessage()} method).
|
||||
* @param cause the cause (which is saved for later retrieval by the
|
||||
* {@link #getCause()} method). (A {@code null} value is
|
||||
* permitted, and indicates that the cause is nonexistent or
|
||||
* unknown.)
|
||||
* @since 1.4
|
||||
*/
|
||||
public BadConfigurationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new runtime exception with the specified cause and a
|
||||
* detail message of {@code (cause==null ? null : cause.toString())}
|
||||
* (which typically contains the class and detail message of
|
||||
* {@code cause}). This constructor is useful for runtime exceptions
|
||||
* that are little more than wrappers for other throwables.
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the
|
||||
* {@link #getCause()} method). (A {@code null} value is
|
||||
* permitted, and indicates that the cause is nonexistent or
|
||||
* unknown.)
|
||||
* @since 1.4
|
||||
*/
|
||||
public BadConfigurationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new runtime exception with the specified detail
|
||||
* message, cause, suppression enabled or disabled, and writable
|
||||
* stack trace enabled or disabled.
|
||||
*
|
||||
* @param message the detail message.
|
||||
* @param cause the cause. (A {@code null} value is permitted,
|
||||
* and indicates that the cause is nonexistent or unknown.)
|
||||
* @param enableSuppression whether or not suppression is enabled
|
||||
* or disabled
|
||||
* @param writableStackTrace whether or not the stack trace should
|
||||
* be writable
|
||||
* @since 1.7
|
||||
*/
|
||||
protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
* 统一异常处理
|
||||
*/
|
||||
@Getter
|
||||
public class BadRequestException extends RuntimeException{
|
||||
|
||||
private Integer status = BAD_REQUEST.value();
|
||||
|
||||
public BadRequestException(String msg){
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public BadRequestException(HttpStatus status,String msg){
|
||||
super(msg);
|
||||
this.status = status.value();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.exception;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public class EntityExistException extends RuntimeException {
|
||||
|
||||
public EntityExistException(Class clazz, String field, String val) {
|
||||
super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
|
||||
}
|
||||
|
||||
private static String generateMessage(String entity, String field, String val) {
|
||||
return StringUtils.capitalize(entity)
|
||||
+ " with " + field + " "+ val + " existed";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.exception;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public class EntityNotFoundException extends RuntimeException {
|
||||
|
||||
public EntityNotFoundException(Class clazz, String field, String val) {
|
||||
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
|
||||
}
|
||||
|
||||
private static String generateMessage(String entity, String field, String val) {
|
||||
return StringUtils.capitalize(entity)
|
||||
+ " with " + field + " "+ val + " does not exist";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.exception.handler;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
@Data
|
||||
class ApiError {
|
||||
|
||||
private Integer status = 400;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime timestamp;
|
||||
private String message;
|
||||
|
||||
private ApiError() {
|
||||
timestamp = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public static ApiError error(String message){
|
||||
ApiError apiError = new ApiError();
|
||||
apiError.setMessage(message);
|
||||
return apiError;
|
||||
}
|
||||
|
||||
public static ApiError error(Integer status, String message){
|
||||
ApiError apiError = new ApiError();
|
||||
apiError.setStatus(status);
|
||||
apiError.setMessage(message);
|
||||
return apiError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.exception.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.exception.EntityExistException;
|
||||
import me.zhengjie.exception.EntityNotFoundException;
|
||||
import me.zhengjie.utils.ThrowableUtil;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import static org.springframework.http.HttpStatus.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 处理所有不可知的异常
|
||||
*/
|
||||
@ExceptionHandler(Throwable.class)
|
||||
public ResponseEntity<ApiError> handleException(Throwable e){
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
return buildResponseEntity(ApiError.error(e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* BadCredentialsException
|
||||
*/
|
||||
@ExceptionHandler(BadCredentialsException.class)
|
||||
public ResponseEntity<ApiError> badCredentialsException(BadCredentialsException e){
|
||||
// 打印堆栈信息
|
||||
String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage();
|
||||
log.error(message);
|
||||
return buildResponseEntity(ApiError.error(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
*/
|
||||
@ExceptionHandler(value = BadRequestException.class)
|
||||
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 EntityExist
|
||||
*/
|
||||
@ExceptionHandler(value = EntityExistException.class)
|
||||
public ResponseEntity<ApiError> entityExistException(EntityExistException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
return buildResponseEntity(ApiError.error(e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 EntityNotFound
|
||||
*/
|
||||
@ExceptionHandler(value = EntityNotFoundException.class)
|
||||
public ResponseEntity<ApiError> entityNotFoundException(EntityNotFoundException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
return buildResponseEntity(ApiError.error(NOT_FOUND.value(),e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理所有接口数据验证异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
|
||||
String message = objectError.getDefaultMessage();
|
||||
if (objectError instanceof FieldError) {
|
||||
message = ((FieldError) objectError).getField() + ": " + message;
|
||||
}
|
||||
return buildResponseEntity(ApiError.error(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一返回
|
||||
*/
|
||||
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
|
||||
return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
/**
|
||||
* @author: liaojinlong
|
||||
* @date: 2020/6/11 15:49
|
||||
* @apiNote: 关于缓存的Key集合
|
||||
*/
|
||||
public interface CacheKey {
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*/
|
||||
String USER_ID = "user::id:";
|
||||
/**
|
||||
* 数据
|
||||
*/
|
||||
String DATA_USER = "data::user:";
|
||||
/**
|
||||
* 菜单
|
||||
*/
|
||||
String MENU_ID = "menu::id:";
|
||||
String MENU_USER = "menu::user:";
|
||||
/**
|
||||
* 角色授权
|
||||
*/
|
||||
String ROLE_AUTH = "role::auth:";
|
||||
/**
|
||||
* 角色信息
|
||||
*/
|
||||
String ROLE_ID = "role::id:";
|
||||
/**
|
||||
* 部门
|
||||
*/
|
||||
String DEPT_ID = "dept::id:";
|
||||
/**
|
||||
* 岗位
|
||||
*/
|
||||
String JOB_ID = "job::id:";
|
||||
/**
|
||||
* 数据字典
|
||||
*/
|
||||
String DICT_NAME = "dict::name:";
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package me.zhengjie.utils;
|
||||
|
||||
/**
|
||||
* @author: liaojinlong
|
||||
* @date: 2020/6/9 17:02
|
||||
* @since: 1.0
|
||||
* @see {@link SpringContextHolder}
|
||||
* 针对某些初始化方法,在SpringContextHolder 初始化前时,<br>
|
||||
* 可提交一个 提交回调任务。<br>
|
||||
* 在SpringContextHolder 初始化后,进行回调使用
|
||||
*/
|
||||
|
||||
public interface CallBack {
|
||||
/**
|
||||
* 回调执行方法
|
||||
*/
|
||||
void executor();
|
||||
|
||||
/**
|
||||
* 本回调任务名称
|
||||
* @return /
|
||||
*/
|
||||
default String getCallBackName() {
|
||||
return Thread.currentThread().getId() + ":" + this.getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @website https://eladmin.vip
|
||||
* @description 用于关闭各种连接,缺啥补啥
|
||||
* @date 2021-03-05
|
||||
**/
|
||||
public class CloseUtil {
|
||||
|
||||
public static void close(Closeable closeable) {
|
||||
if (null != closeable) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (Exception e) {
|
||||
// 静默关闭
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void close(AutoCloseable closeable) {
|
||||
if (null != closeable) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (Exception e) {
|
||||
// 静默关闭
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: liaojinlong
|
||||
* @date: 2020/6/11 16:28
|
||||
* @apiNote: JDK 8 新日期类 格式化与字符串转换 工具类
|
||||
*/
|
||||
public class DateUtil {
|
||||
|
||||
public static final DateTimeFormatter DFY_MD_HMS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
public static final DateTimeFormatter DFY_MD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* LocalDateTime 转时间戳
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @return /
|
||||
*/
|
||||
public static Long getTimeStamp(LocalDateTime localDateTime) {
|
||||
return localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳转LocalDateTime
|
||||
*
|
||||
* @param timeStamp /
|
||||
* @return /
|
||||
*/
|
||||
public static LocalDateTime fromTimeStamp(Long timeStamp) {
|
||||
return LocalDateTime.ofEpochSecond(timeStamp, 0, OffsetDateTime.now().getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalDateTime 转 Date
|
||||
* Jdk8 后 不推荐使用 {@link Date} Date
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @return /
|
||||
*/
|
||||
public static Date toDate(LocalDateTime localDateTime) {
|
||||
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* LocalDate 转 Date
|
||||
* Jdk8 后 不推荐使用 {@link Date} Date
|
||||
*
|
||||
* @param localDate /
|
||||
* @return /
|
||||
*/
|
||||
public static Date toDate(LocalDate localDate) {
|
||||
return toDate(localDate.atTime(LocalTime.now(ZoneId.systemDefault())));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Date转 LocalDateTime
|
||||
* Jdk8 后 不推荐使用 {@link Date} Date
|
||||
*
|
||||
* @param date /
|
||||
* @return /
|
||||
*/
|
||||
public static LocalDateTime toLocalDateTime(Date date) {
|
||||
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期 格式化
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @param patten /
|
||||
* @return /
|
||||
*/
|
||||
public static String localDateTimeFormat(LocalDateTime localDateTime, String patten) {
|
||||
DateTimeFormatter df = DateTimeFormatter.ofPattern(patten);
|
||||
return df.format(localDateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期 格式化
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @param df /
|
||||
* @return /
|
||||
*/
|
||||
public static String localDateTimeFormat(LocalDateTime localDateTime, DateTimeFormatter df) {
|
||||
return df.format(localDateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式化 yyyy-MM-dd HH:mm:ss
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @return /
|
||||
*/
|
||||
public static String localDateTimeFormatyMdHms(LocalDateTime localDateTime) {
|
||||
return DFY_MD_HMS.format(localDateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式化 yyyy-MM-dd
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @return /
|
||||
*/
|
||||
public String localDateTimeFormatyMd(LocalDateTime localDateTime) {
|
||||
return DFY_MD.format(localDateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @return /
|
||||
*/
|
||||
public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, String pattern) {
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
|
||||
return LocalDateTime.from(dateTimeFormatter.parse(localDateTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @return /
|
||||
*/
|
||||
public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, DateTimeFormatter dateTimeFormatter) {
|
||||
return LocalDateTime.from(dateTimeFormatter.parse(localDateTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd HH:mm:ss
|
||||
*
|
||||
* @param localDateTime /
|
||||
* @return /
|
||||
*/
|
||||
public static LocalDateTime parseLocalDateTimeFormatyMdHms(String localDateTime) {
|
||||
return LocalDateTime.from(DFY_MD_HMS.parse(localDateTime));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
/**
|
||||
* 常用静态常量
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-26
|
||||
*/
|
||||
public class ElAdminConstant {
|
||||
|
||||
/**
|
||||
* 用于IP定位转换
|
||||
*/
|
||||
public static final String REGION = "内网IP|内网IP";
|
||||
/**
|
||||
* win 系统
|
||||
*/
|
||||
public static final String WIN = "win";
|
||||
|
||||
/**
|
||||
* mac 系统
|
||||
*/
|
||||
public static final String MAC = "mac";
|
||||
|
||||
/**
|
||||
* 常用接口
|
||||
*/
|
||||
public static class Url {
|
||||
// IP归属地查询
|
||||
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?ip=%s&json=true";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 加密
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
|
||||
public class EncryptUtils {
|
||||
|
||||
private static final String STR_PARAM = "Passw0rd";
|
||||
|
||||
private static Cipher cipher;
|
||||
|
||||
private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
private static DESKeySpec getDesKeySpec(String source) throws Exception {
|
||||
if (source == null || source.length() == 0){
|
||||
return null;
|
||||
}
|
||||
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
|
||||
String strKey = "Passw0rd";
|
||||
return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对称加密
|
||||
*/
|
||||
public static String desEncrypt(String source) throws Exception {
|
||||
DESKeySpec desKeySpec = getDesKeySpec(source);
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
|
||||
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV);
|
||||
return byte2hex(
|
||||
cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对称解密
|
||||
*/
|
||||
public static String desDecrypt(String source) throws Exception {
|
||||
byte[] src = hex2byte(source.getBytes(StandardCharsets.UTF_8));
|
||||
DESKeySpec desKeySpec = getDesKeySpec(source);
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
|
||||
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, IV);
|
||||
byte[] retByte = cipher.doFinal(src);
|
||||
return new String(retByte);
|
||||
}
|
||||
|
||||
private static String byte2hex(byte[] inStr) {
|
||||
String stmp;
|
||||
StringBuilder out = new StringBuilder(inStr.length * 2);
|
||||
for (byte b : inStr) {
|
||||
stmp = Integer.toHexString(b & 0xFF);
|
||||
if (stmp.length() == 1) {
|
||||
// 如果是0至F的单位字符串,则添加0
|
||||
out.append("0").append(stmp);
|
||||
} else {
|
||||
out.append(stmp);
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static byte[] hex2byte(byte[] b) {
|
||||
int size = 2;
|
||||
if ((b.length % size) != 0){
|
||||
throw new IllegalArgumentException("长度不是偶数");
|
||||
}
|
||||
byte[] b2 = new byte[b.length / 2];
|
||||
for (int n = 0; n < b.length; n += size) {
|
||||
String item = new String(b, n, 2);
|
||||
b2[n / 2] = (byte) Integer.parseInt(item, 16);
|
||||
}
|
||||
return b2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.poi.excel.BigExcelWriter;
|
||||
import cn.hutool.poi.excel.ExcelUtil;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.xssf.streaming.SXSSFSheet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.security.MessageDigest;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* File工具类,扩展 hutool 工具包
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-27
|
||||
*/
|
||||
public class FileUtil extends cn.hutool.core.io.FileUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
|
||||
|
||||
/**
|
||||
* 系统临时目录
|
||||
* <br>
|
||||
* windows 包含路径分割符,但Linux 不包含,
|
||||
* 在windows \\==\ 前提下,
|
||||
* 为安全起见 同意拼装 路径分割符,
|
||||
* <pre>
|
||||
* java.io.tmpdir
|
||||
* windows : C:\Users/xxx\AppData\Local\Temp\
|
||||
* linux: /temp
|
||||
* </pre>
|
||||
*/
|
||||
public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
|
||||
/**
|
||||
* 定义GB的计算常量
|
||||
*/
|
||||
private static final int GB = 1024 * 1024 * 1024;
|
||||
/**
|
||||
* 定义MB的计算常量
|
||||
*/
|
||||
private static final int MB = 1024 * 1024;
|
||||
/**
|
||||
* 定义KB的计算常量
|
||||
*/
|
||||
private static final int KB = 1024;
|
||||
|
||||
/**
|
||||
* 格式化小数
|
||||
*/
|
||||
private static final DecimalFormat DF = new DecimalFormat("0.00");
|
||||
|
||||
public static final String IMAGE = "图片";
|
||||
public static final String TXT = "文档";
|
||||
public static final String MUSIC = "音乐";
|
||||
public static final String VIDEO = "视频";
|
||||
public static final String OTHER = "其他";
|
||||
|
||||
|
||||
/**
|
||||
* MultipartFile转File
|
||||
*/
|
||||
public static File toFile(MultipartFile multipartFile) {
|
||||
// 获取文件名
|
||||
String fileName = multipartFile.getOriginalFilename();
|
||||
// 获取文件后缀
|
||||
String prefix = "." + getExtensionName(fileName);
|
||||
File file = null;
|
||||
try {
|
||||
// 用uuid作为文件名,防止生成的临时文件重复
|
||||
file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix);
|
||||
// MultipartFile to File
|
||||
multipartFile.transferTo(file);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名,不带 .
|
||||
*/
|
||||
public static String getExtensionName(String filename) {
|
||||
if ((filename != null) && (filename.length() > 0)) {
|
||||
int dot = filename.lastIndexOf('.');
|
||||
if ((dot > -1) && (dot < (filename.length() - 1))) {
|
||||
return filename.substring(dot + 1);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Java文件操作 获取不带扩展名的文件名
|
||||
*/
|
||||
public static String getFileNameNoEx(String filename) {
|
||||
if ((filename != null) && (filename.length() > 0)) {
|
||||
int dot = filename.lastIndexOf('.');
|
||||
if ((dot > -1) && (dot < (filename.length()))) {
|
||||
return filename.substring(0, dot);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件大小转换
|
||||
*/
|
||||
public static String getSize(long size) {
|
||||
String resultSize;
|
||||
if (size / GB >= 1) {
|
||||
//如果当前Byte的值大于等于1GB
|
||||
resultSize = DF.format(size / (float) GB) + "GB ";
|
||||
} else if (size / MB >= 1) {
|
||||
//如果当前Byte的值大于等于1MB
|
||||
resultSize = DF.format(size / (float) MB) + "MB ";
|
||||
} else if (size / KB >= 1) {
|
||||
//如果当前Byte的值大于等于1KB
|
||||
resultSize = DF.format(size / (float) KB) + "KB ";
|
||||
} else {
|
||||
resultSize = size + "B ";
|
||||
}
|
||||
return resultSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* inputStream 转 File
|
||||
*/
|
||||
static File inputStreamToFile(InputStream ins, String name){
|
||||
File file = new File(SYS_TEM_DIR + name);
|
||||
if (file.exists()) {
|
||||
return file;
|
||||
}
|
||||
OutputStream os = null;
|
||||
try {
|
||||
os = new FileOutputStream(file);
|
||||
int bytesRead;
|
||||
int len = 8192;
|
||||
byte[] buffer = new byte[len];
|
||||
while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
CloseUtil.close(os);
|
||||
CloseUtil.close(ins);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件名解析成文件的上传路径
|
||||
*/
|
||||
public static File upload(MultipartFile file, String filePath) {
|
||||
Date date = new Date();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
|
||||
String name = getFileNameNoEx(file.getOriginalFilename());
|
||||
String suffix = getExtensionName(file.getOriginalFilename());
|
||||
String nowStr = "-" + format.format(date);
|
||||
try {
|
||||
String fileName = name + nowStr + "." + suffix;
|
||||
String path = filePath + fileName;
|
||||
// getCanonicalFile 可解析正确各种路径
|
||||
File dest = new File(path).getCanonicalFile();
|
||||
// 检测是否存在目录
|
||||
if (!dest.getParentFile().exists()) {
|
||||
if (!dest.getParentFile().mkdirs()) {
|
||||
System.out.println("was not successful.");
|
||||
}
|
||||
}
|
||||
// 文件写入
|
||||
file.transferTo(dest);
|
||||
return dest;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel
|
||||
*/
|
||||
public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException {
|
||||
String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx";
|
||||
File file = new File(tempPath);
|
||||
BigExcelWriter writer = ExcelUtil.getBigWriter(file);
|
||||
// 一次性写出内容,使用默认样式,强制输出标题
|
||||
writer.write(list, true);
|
||||
SXSSFSheet sheet = (SXSSFSheet)writer.getSheet();
|
||||
//上面需要强转SXSSFSheet 不然没有trackAllColumnsForAutoSizing方法
|
||||
sheet.trackAllColumnsForAutoSizing();
|
||||
//列宽自适应
|
||||
writer.autoSizeColumnAll();
|
||||
//response为HttpServletResponse对象
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
|
||||
//test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
|
||||
response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
// 终止后删除临时文件
|
||||
file.deleteOnExit();
|
||||
writer.flush(out, true);
|
||||
//此处记得关闭输出Servlet流
|
||||
IoUtil.close(out);
|
||||
}
|
||||
|
||||
public static String getFileType(String type) {
|
||||
String documents = "txt doc pdf ppt pps xlsx xls docx";
|
||||
String music = "mp3 wav wma mpa ram ra aac aif m4a";
|
||||
String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
|
||||
String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
|
||||
if (image.contains(type)) {
|
||||
return IMAGE;
|
||||
} else if (documents.contains(type)) {
|
||||
return TXT;
|
||||
} else if (music.contains(type)) {
|
||||
return MUSIC;
|
||||
} else if (video.contains(type)) {
|
||||
return VIDEO;
|
||||
} else {
|
||||
return OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkSize(long maxSize, long size) {
|
||||
// 1M
|
||||
int len = 1024 * 1024;
|
||||
if (size > (maxSize * len)) {
|
||||
throw new BadRequestException("文件超出规定大小:" + maxSize + "MB");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两个文件是否相同
|
||||
*/
|
||||
public static boolean check(File file1, File file2) {
|
||||
String img1Md5 = getMd5(file1);
|
||||
String img2Md5 = getMd5(file2);
|
||||
if(img1Md5 != null){
|
||||
return img1Md5.equals(img2Md5);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两个文件是否相同
|
||||
*/
|
||||
public static boolean check(String file1Md5, String file2Md5) {
|
||||
return file1Md5.equals(file2Md5);
|
||||
}
|
||||
|
||||
private static byte[] getByte(File file) {
|
||||
// 得到文件长度
|
||||
byte[] b = new byte[(int) file.length()];
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(file);
|
||||
try {
|
||||
System.out.println(in.read(b));
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
} finally {
|
||||
CloseUtil.close(in);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private static String getMd5(byte[] bytes) {
|
||||
// 16进制字符
|
||||
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
try {
|
||||
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
|
||||
mdTemp.update(bytes);
|
||||
byte[] md = mdTemp.digest();
|
||||
int j = md.length;
|
||||
char[] str = new char[j * 2];
|
||||
int k = 0;
|
||||
// 移位 输出字符串
|
||||
for (byte byte0 : md) {
|
||||
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
|
||||
str[k++] = hexDigits[byte0 & 0xf];
|
||||
}
|
||||
return new String(str);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
* @param request /
|
||||
* @param response /
|
||||
* @param file /
|
||||
*/
|
||||
public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) {
|
||||
response.setCharacterEncoding(request.getCharacterEncoding());
|
||||
response.setContentType("application/octet-stream");
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
|
||||
IOUtils.copy(fis, response.getOutputStream());
|
||||
response.flushBuffer();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
if (deleteOnExit) {
|
||||
file.deleteOnExit();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getMd5(File file) {
|
||||
return getMd5(getByte(file));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 分页工具
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-10
|
||||
*/
|
||||
public class PageUtil extends cn.hutool.core.util.PageUtil {
|
||||
|
||||
/**
|
||||
* List 分页
|
||||
*/
|
||||
public static List toPage(int page, int size , List list) {
|
||||
int fromIndex = page * size;
|
||||
int toIndex = page * size + size;
|
||||
if(fromIndex > list.size()){
|
||||
return new ArrayList();
|
||||
} else if(toIndex >= list.size()) {
|
||||
return list.subList(fromIndex,list.size());
|
||||
} else {
|
||||
return list.subList(fromIndex,toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Page 数据处理,预防redis反序列化报错
|
||||
*/
|
||||
public static Map<String,Object> toPage(Page page) {
|
||||
Map<String,Object> map = new LinkedHashMap<>(2);
|
||||
map.put("content",page.getContent());
|
||||
map.put("totalElements",page.getTotalElements());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义分页
|
||||
*/
|
||||
public static Map<String,Object> toPage(Object object, Object totalElements) {
|
||||
Map<String,Object> map = new LinkedHashMap<>(2);
|
||||
map.put("content",object);
|
||||
map.put("totalElements",totalElements);
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.annotation.DataPermission;
|
||||
import me.zhengjie.annotation.Query;
|
||||
import javax.persistence.criteria.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-6-4 14:59:48
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings({"unchecked","all"})
|
||||
public class QueryHelp {
|
||||
|
||||
public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) {
|
||||
List<Predicate> list = new ArrayList<>();
|
||||
if(query == null){
|
||||
return cb.and(list.toArray(new Predicate[0]));
|
||||
}
|
||||
// 数据权限验证
|
||||
DataPermission permission = query.getClass().getAnnotation(DataPermission.class);
|
||||
if(permission != null){
|
||||
// 获取数据权限
|
||||
List<Long> dataScopes = SecurityUtils.getCurrentUserDataScope();
|
||||
if(CollectionUtil.isNotEmpty(dataScopes)){
|
||||
if(StringUtils.isNotBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) {
|
||||
Join join = root.join(permission.joinName(), JoinType.LEFT);
|
||||
list.add(getExpression(permission.fieldName(),join, root).in(dataScopes));
|
||||
} else if (StringUtils.isBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) {
|
||||
list.add(getExpression(permission.fieldName(),null, root).in(dataScopes));
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
|
||||
for (Field field : fields) {
|
||||
boolean accessible = field.isAccessible();
|
||||
// 设置对象的访问权限,保证对private的属性的访
|
||||
field.setAccessible(true);
|
||||
Query q = field.getAnnotation(Query.class);
|
||||
if (q != null) {
|
||||
String propName = q.propName();
|
||||
String joinName = q.joinName();
|
||||
String blurry = q.blurry();
|
||||
String attributeName = isBlank(propName) ? field.getName() : propName;
|
||||
Class<?> fieldType = field.getType();
|
||||
Object val = field.get(query);
|
||||
if (ObjectUtil.isNull(val) || "".equals(val)) {
|
||||
continue;
|
||||
}
|
||||
Join join = null;
|
||||
// 模糊多字段
|
||||
if (ObjectUtil.isNotEmpty(blurry)) {
|
||||
String[] blurrys = blurry.split(",");
|
||||
List<Predicate> orPredicate = new ArrayList<>();
|
||||
for (String s : blurrys) {
|
||||
orPredicate.add(cb.like(root.get(s)
|
||||
.as(String.class), "%" + val.toString() + "%"));
|
||||
}
|
||||
Predicate[] p = new Predicate[orPredicate.size()];
|
||||
list.add(cb.or(orPredicate.toArray(p)));
|
||||
continue;
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(joinName)) {
|
||||
String[] joinNames = joinName.split(">");
|
||||
for (String name : joinNames) {
|
||||
switch (q.join()) {
|
||||
case LEFT:
|
||||
if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){
|
||||
join = join.join(name, JoinType.LEFT);
|
||||
} else {
|
||||
join = root.join(name, JoinType.LEFT);
|
||||
}
|
||||
break;
|
||||
case RIGHT:
|
||||
if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){
|
||||
join = join.join(name, JoinType.RIGHT);
|
||||
} else {
|
||||
join = root.join(name, JoinType.RIGHT);
|
||||
}
|
||||
break;
|
||||
case INNER:
|
||||
if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){
|
||||
join = join.join(name, JoinType.INNER);
|
||||
} else {
|
||||
join = root.join(name, JoinType.INNER);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (q.type()) {
|
||||
case EQUAL:
|
||||
list.add(cb.equal(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType),val));
|
||||
break;
|
||||
case GREATER_THAN:
|
||||
list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
|
||||
break;
|
||||
case LESS_THAN:
|
||||
list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
|
||||
break;
|
||||
case LESS_THAN_NQ:
|
||||
list.add(cb.lessThan(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
|
||||
break;
|
||||
case INNER_LIKE:
|
||||
list.add(cb.like(getExpression(attributeName,join,root)
|
||||
.as(String.class), "%" + val.toString() + "%"));
|
||||
break;
|
||||
case LEFT_LIKE:
|
||||
list.add(cb.like(getExpression(attributeName,join,root)
|
||||
.as(String.class), "%" + val.toString()));
|
||||
break;
|
||||
case RIGHT_LIKE:
|
||||
list.add(cb.like(getExpression(attributeName,join,root)
|
||||
.as(String.class), val.toString() + "%"));
|
||||
break;
|
||||
case IN:
|
||||
if (CollUtil.isNotEmpty((Collection<Object>)val)) {
|
||||
list.add(getExpression(attributeName,join,root).in((Collection<Object>) val));
|
||||
}
|
||||
break;
|
||||
case NOT_IN:
|
||||
if (CollUtil.isNotEmpty((Collection<Object>)val)) {
|
||||
list.add(getExpression(attributeName,join,root).in((Collection<Object>) val).not());
|
||||
}
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
list.add(cb.notEqual(getExpression(attributeName,join,root), val));
|
||||
break;
|
||||
case NOT_NULL:
|
||||
list.add(cb.isNotNull(getExpression(attributeName,join,root)));
|
||||
break;
|
||||
case IS_NULL:
|
||||
list.add(cb.isNull(getExpression(attributeName,join,root)));
|
||||
break;
|
||||
case BETWEEN:
|
||||
List<Object> between = new ArrayList<>((List<Object>)val);
|
||||
list.add(cb.between(getExpression(attributeName, join, root).as((Class<? extends Comparable>) between.get(0).getClass()),
|
||||
(Comparable) between.get(0), (Comparable) between.get(1)));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
field.setAccessible(accessible);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
int size = list.size();
|
||||
return cb.and(list.toArray(new Predicate[size]));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T, R> Expression<T> getExpression(String attributeName, Join join, Root<R> root) {
|
||||
if (ObjectUtil.isNotEmpty(join)) {
|
||||
return join.get(attributeName);
|
||||
} else {
|
||||
return root.get(attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBlank(final CharSequence cs) {
|
||||
int strLen;
|
||||
if (cs == null || (strLen = cs.length()) == 0) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
if (!Character.isWhitespace(cs.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<Field> getAllFields(Class clazz, List<Field> fields) {
|
||||
if (clazz != null) {
|
||||
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
||||
getAllFields(clazz.getSuperclass(), fields);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,712 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Component
|
||||
@SuppressWarnings({"unchecked", "all"})
|
||||
public class RedisUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(RedisUtils.class);
|
||||
private RedisTemplate<Object, Object> redisTemplate;
|
||||
@Value("${jwt.online-key}")
|
||||
private String onlineKey;
|
||||
|
||||
public RedisUtils(RedisTemplate<Object, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
this.redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
this.redisTemplate.setStringSerializer(new StringRedisSerializer());
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
*/
|
||||
public boolean expire(String key, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @param timeUnit 单位
|
||||
*/
|
||||
public boolean expire(String key, long time, TimeUnit timeUnit) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.expire(key, time, timeUnit);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 key 获取过期时间
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @return 时间(秒) 返回0代表为永久有效
|
||||
*/
|
||||
public long getExpire(Object key) {
|
||||
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找匹配key
|
||||
*
|
||||
* @param pattern key
|
||||
* @return /
|
||||
*/
|
||||
public List<String> scan(String pattern) {
|
||||
ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
|
||||
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
|
||||
RedisConnection rc = Objects.requireNonNull(factory).getConnection();
|
||||
Cursor<byte[]> cursor = rc.scan(options);
|
||||
List<String> result = new ArrayList<>();
|
||||
while (cursor.hasNext()) {
|
||||
result.add(new String(cursor.next()));
|
||||
}
|
||||
try {
|
||||
RedisConnectionUtils.releaseConnection(rc, factory);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询 key
|
||||
*
|
||||
* @param patternKey key
|
||||
* @param page 页码
|
||||
* @param size 每页数目
|
||||
* @return /
|
||||
*/
|
||||
public List<String> findKeysForPage(String patternKey, int page, int size) {
|
||||
ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
|
||||
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
|
||||
RedisConnection rc = Objects.requireNonNull(factory).getConnection();
|
||||
Cursor<byte[]> cursor = rc.scan(options);
|
||||
List<String> result = new ArrayList<>(size);
|
||||
int tmpIndex = 0;
|
||||
int fromIndex = page * size;
|
||||
int toIndex = page * size + size;
|
||||
while (cursor.hasNext()) {
|
||||
if (tmpIndex >= fromIndex && tmpIndex < toIndex) {
|
||||
result.add(new String(cursor.next()));
|
||||
tmpIndex++;
|
||||
continue;
|
||||
}
|
||||
// 获取到满足条件的数据后,就可以退出了
|
||||
if (tmpIndex >= toIndex) {
|
||||
break;
|
||||
}
|
||||
tmpIndex++;
|
||||
cursor.next();
|
||||
}
|
||||
try {
|
||||
RedisConnectionUtils.releaseConnection(rc, factory);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
try {
|
||||
return redisTemplate.hasKey(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
*
|
||||
* @param key 可以传一个值 或多个
|
||||
*/
|
||||
public void del(String... keys) {
|
||||
if (keys != null && keys.length > 0) {
|
||||
if (keys.length == 1) {
|
||||
boolean result = redisTemplate.delete(keys[0]);
|
||||
log.debug("--------------------------------------------");
|
||||
log.debug(new StringBuilder("删除缓存:").append(keys[0]).append(",结果:").append(result).toString());
|
||||
log.debug("--------------------------------------------");
|
||||
} else {
|
||||
Set<Object> keySet = new HashSet<>();
|
||||
for (String key : keys) {
|
||||
keySet.addAll(redisTemplate.keys(key));
|
||||
}
|
||||
long count = redisTemplate.delete(keySet);
|
||||
log.debug("--------------------------------------------");
|
||||
log.debug("成功删除缓存:" + keySet.toString());
|
||||
log.debug("缓存删除数量:" + count + "个");
|
||||
log.debug("--------------------------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================String=============================
|
||||
|
||||
/**
|
||||
* 普通缓存获取
|
||||
*
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return key == null ? null : redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取
|
||||
*
|
||||
* @param keys
|
||||
* @return
|
||||
*/
|
||||
public List<Object> multiGet(List<String> keys) {
|
||||
List list = redisTemplate.opsForValue().multiGet(Sets.newHashSet(keys));
|
||||
List resultList = Lists.newArrayList();
|
||||
Optional.ofNullable(list).ifPresent(e-> list.forEach(ele-> Optional.ofNullable(ele).ifPresent(resultList::add)));
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean set(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public boolean set(String key, Object value, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
} else {
|
||||
set(key, value);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间
|
||||
* @param timeUnit 类型
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, timeUnit);
|
||||
} else {
|
||||
set(key, value);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================Map=================================
|
||||
|
||||
/**
|
||||
* HashGet
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 不能为null
|
||||
* @return 值
|
||||
*/
|
||||
public Object hget(String key, String item) {
|
||||
return redisTemplate.opsForHash().get(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取hashKey对应的所有键值
|
||||
*
|
||||
* @param key 键
|
||||
* @return 对应的多个键值
|
||||
*/
|
||||
public Map<Object, Object> hmget(String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @return true 成功 false 失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet 并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @param time 时间(秒)
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除hash表中的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 可以使多个 不能为null
|
||||
*/
|
||||
public void hdel(String key, Object... item) {
|
||||
redisTemplate.opsForHash().delete(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断hash表中是否有该项的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 不能为null
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hHasKey(String key, String item) {
|
||||
return redisTemplate.opsForHash().hasKey(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要增加几(大于0)
|
||||
* @return
|
||||
*/
|
||||
public double hincr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, by);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递减
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要减少记(小于0)
|
||||
* @return
|
||||
*/
|
||||
public double hdecr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||
}
|
||||
|
||||
// ============================set=============================
|
||||
|
||||
/**
|
||||
* 根据key获取Set中的所有值
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public Set<Object> sGet(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据value从一个set中查询,是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean sHasKey(String key, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().isMember(key, value);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据放入set缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSet(String key, Object... values) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().add(key, values);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将set数据放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSetAndTime(String key, long time, Object... values) {
|
||||
try {
|
||||
Long count = redisTemplate.opsForSet().add(key, values);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return count;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取set缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long sGetSetSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().size(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除值为value的
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long setRemove(String key, Object... values) {
|
||||
try {
|
||||
Long count = redisTemplate.opsForSet().remove(key, values);
|
||||
return count;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ===============================list=================================
|
||||
|
||||
/**
|
||||
* 获取list缓存的内容
|
||||
*
|
||||
* @param key 键
|
||||
* @param start 开始
|
||||
* @param end 结束 0 到 -1代表所有值
|
||||
* @return
|
||||
*/
|
||||
public List<Object> lGet(String key, long start, long end) {
|
||||
try {
|
||||
return redisTemplate.opsForList().range(key, start, end);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取list缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long lGetListSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForList().size(key);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过索引 获取list中的值
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
|
||||
* @return
|
||||
*/
|
||||
public Object lGetIndex(String key, long index) {
|
||||
try {
|
||||
return redisTemplate.opsForList().index(key, index);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引修改list中的某条数据
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引
|
||||
* @param value 值
|
||||
* @return /
|
||||
*/
|
||||
public boolean lUpdateIndex(String key, long index, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().set(key, index, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除N个值为value
|
||||
*
|
||||
* @param key 键
|
||||
* @param count 移除多少个
|
||||
* @param value 值
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long lRemove(String key, long count, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForList().remove(key, count, value);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param prefix 前缀
|
||||
* @param ids id
|
||||
*/
|
||||
public void delByKeys(String prefix, Set<Long> ids) {
|
||||
Set<Object> keys = new HashSet<>();
|
||||
for (Long id : ids) {
|
||||
keys.addAll(redisTemplate.keys(new StringBuffer(prefix).append(id).toString()));
|
||||
}
|
||||
long count = redisTemplate.delete(keys);
|
||||
// 此处提示可自行删除
|
||||
log.debug("--------------------------------------------");
|
||||
log.debug("成功删除缓存:" + keys.toString());
|
||||
log.debug("缓存删除数量:" + count + "个");
|
||||
log.debug("--------------------------------------------");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 获取 HttpServletRequest
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
public class RequestHolder {
|
||||
|
||||
public static HttpServletRequest getHttpServletRequest() {
|
||||
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
package me.zhengjie.utils;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.*;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
* @author https://www.cnblogs.com/nihaorz/p/10690643.html
|
||||
* @description Rsa 工具类,公钥私钥生成,加解密
|
||||
* @date 2020-05-18
|
||||
**/
|
||||
public class RsaUtils {
|
||||
|
||||
private static final String SRC = "123456";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("\n");
|
||||
RsaKeyPair keyPair = generateKeyPair();
|
||||
System.out.println("公钥:" + keyPair.getPublicKey());
|
||||
System.out.println("私钥:" + keyPair.getPrivateKey());
|
||||
System.out.println("\n");
|
||||
test1(keyPair);
|
||||
System.out.println("\n");
|
||||
test2(keyPair);
|
||||
System.out.println("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥加密私钥解密
|
||||
*/
|
||||
private static void test1(RsaKeyPair keyPair) throws Exception {
|
||||
System.out.println("***************** 公钥加密私钥解密开始 *****************");
|
||||
String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC);
|
||||
String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1);
|
||||
System.out.println("加密前:" + RsaUtils.SRC);
|
||||
System.out.println("加密后:" + text1);
|
||||
System.out.println("解密后:" + text2);
|
||||
if (RsaUtils.SRC.equals(text2)) {
|
||||
System.out.println("解密字符串和原始字符串一致,解密成功");
|
||||
} else {
|
||||
System.out.println("解密字符串和原始字符串不一致,解密失败");
|
||||
}
|
||||
System.out.println("***************** 公钥加密私钥解密结束 *****************");
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥加密公钥解密
|
||||
* @throws Exception /
|
||||
*/
|
||||
private static void test2(RsaKeyPair keyPair) throws Exception {
|
||||
System.out.println("***************** 私钥加密公钥解密开始 *****************");
|
||||
String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC);
|
||||
String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1);
|
||||
System.out.println("加密前:" + RsaUtils.SRC);
|
||||
System.out.println("加密后:" + text1);
|
||||
System.out.println("解密后:" + text2);
|
||||
if (RsaUtils.SRC.equals(text2)) {
|
||||
System.out.println("解密字符串和原始字符串一致,解密成功");
|
||||
} else {
|
||||
System.out.println("解密字符串和原始字符串不一致,解密失败");
|
||||
}
|
||||
System.out.println("***************** 私钥加密公钥解密结束 *****************");
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥解密
|
||||
*
|
||||
* @param publicKeyText 公钥
|
||||
* @param text 待解密的信息
|
||||
* @return /
|
||||
* @throws Exception /
|
||||
*/
|
||||
public static String decryptByPublicKey(String publicKeyText, String text) throws Exception {
|
||||
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, publicKey);
|
||||
byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text));
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥加密
|
||||
*
|
||||
* @param privateKeyText 私钥
|
||||
* @param text 待加密的信息
|
||||
* @return /
|
||||
* @throws Exception /
|
||||
*/
|
||||
public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
|
||||
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
|
||||
byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes());
|
||||
return Base64.encodeBase64String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私钥解密
|
||||
*
|
||||
* @param privateKeyText 私钥
|
||||
* @param text 待解密的文本
|
||||
* @return /
|
||||
* @throws Exception /
|
||||
*/
|
||||
public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
|
||||
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text));
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公钥加密
|
||||
*
|
||||
* @param publicKeyText 公钥
|
||||
* @param text 待加密的文本
|
||||
* @return /
|
||||
*/
|
||||
public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
|
||||
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes());
|
||||
return Base64.encodeBase64String(result);
|
||||
}
|
||||
|
||||
private static byte[] doLongerCipherFinal(int opMode,Cipher cipher, byte[] source) throws Exception {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
if (opMode == Cipher.DECRYPT_MODE) {
|
||||
out.write(cipher.doFinal(source));
|
||||
} else {
|
||||
int offset = 0;
|
||||
int totalSize = source.length;
|
||||
while (totalSize - offset > 0) {
|
||||
int size = Math.min(cipher.getOutputSize(0) - 11, totalSize - offset);
|
||||
out.write(cipher.doFinal(source, offset, size));
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建RSA密钥对
|
||||
*
|
||||
* @return /
|
||||
* @throws NoSuchAlgorithmException /
|
||||
*/
|
||||
public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(1024);
|
||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
|
||||
String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
|
||||
return new RsaKeyPair(publicKeyString, privateKeyString);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RSA密钥对对象
|
||||
*/
|
||||
public static class RsaKeyPair {
|
||||
|
||||
private final String publicKey;
|
||||
private final String privateKey;
|
||||
|
||||
public RsaKeyPair(String publicKey, String privateKey) {
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.utils.enums.DataScopeEnum;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 获取当前登录的用户
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-17
|
||||
*/
|
||||
@Slf4j
|
||||
public class SecurityUtils {
|
||||
|
||||
/**
|
||||
* 获取当前登录的用户
|
||||
* @return UserDetails
|
||||
*/
|
||||
public static UserDetails getCurrentUser() {
|
||||
UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class);
|
||||
return userDetailsService.loadUserByUsername(getCurrentUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户名称
|
||||
*
|
||||
* @return 系统用户名称
|
||||
*/
|
||||
public static String getCurrentUsername() {
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null) {
|
||||
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");
|
||||
}
|
||||
if (authentication.getPrincipal() instanceof UserDetails) {
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
return userDetails.getUsername();
|
||||
}
|
||||
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户ID
|
||||
* @return 系统用户ID
|
||||
*/
|
||||
public static Long getCurrentUserId() {
|
||||
UserDetails userDetails = getCurrentUser();
|
||||
return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的数据权限
|
||||
* @return /
|
||||
*/
|
||||
public static List<Long> getCurrentUserDataScope(){
|
||||
UserDetails userDetails = getCurrentUser();
|
||||
JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes"));
|
||||
return JSONUtil.toList(array,Long.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据权限级别
|
||||
* @return 级别
|
||||
*/
|
||||
public static String getDataScopeType() {
|
||||
List<Long> dataScopes = getCurrentUserDataScope();
|
||||
if(dataScopes.size() != 0){
|
||||
return "";
|
||||
}
|
||||
return DataScopeEnum.ALL.getValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
|
||||
|
||||
private static ApplicationContext applicationContext = null;
|
||||
private static final List<CallBack> CALL_BACKS = new ArrayList<>();
|
||||
private static boolean addCallback = true;
|
||||
|
||||
/**
|
||||
* 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。
|
||||
* 在SpringContextHolder 初始化后,进行回调使用
|
||||
*
|
||||
* @param callBack 回调函数
|
||||
*/
|
||||
public synchronized static void addCallBacks(CallBack callBack) {
|
||||
if (addCallback) {
|
||||
SpringContextHolder.CALL_BACKS.add(callBack);
|
||||
} else {
|
||||
log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName());
|
||||
callBack.executor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getBean(String name) {
|
||||
assertContextInjected();
|
||||
return (T) applicationContext.getBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(Class<T> requiredType) {
|
||||
assertContextInjected();
|
||||
return applicationContext.getBean(requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SpringBoot 配置信息
|
||||
*
|
||||
* @param property 属性key
|
||||
* @param defaultValue 默认值
|
||||
* @param requiredType 返回类型
|
||||
* @return /
|
||||
*/
|
||||
public static <T> T getProperties(String property, T defaultValue, Class<T> requiredType) {
|
||||
T result = defaultValue;
|
||||
try {
|
||||
result = getBean(Environment.class).getProperty(property, requiredType);
|
||||
} catch (Exception ignored) {}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SpringBoot 配置信息
|
||||
*
|
||||
* @param property 属性key
|
||||
* @return /
|
||||
*/
|
||||
public static String getProperties(String property) {
|
||||
return getProperties(property, null, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SpringBoot 配置信息
|
||||
*
|
||||
* @param property 属性key
|
||||
* @param requiredType 返回类型
|
||||
* @return /
|
||||
*/
|
||||
public static <T> T getProperties(String property, Class<T> requiredType) {
|
||||
return getProperties(property, null, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查ApplicationContext不为空.
|
||||
*/
|
||||
private static void assertContextInjected() {
|
||||
if (applicationContext == null) {
|
||||
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
|
||||
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除SpringContextHolder中的ApplicationContext为Null.
|
||||
*/
|
||||
private static void clearHolder() {
|
||||
log.debug("清除SpringContextHolder中的ApplicationContext:"
|
||||
+ applicationContext);
|
||||
applicationContext = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
SpringContextHolder.clearHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
if (SpringContextHolder.applicationContext != null) {
|
||||
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
|
||||
}
|
||||
SpringContextHolder.applicationContext = applicationContext;
|
||||
if (addCallback) {
|
||||
for (CallBack callBack : SpringContextHolder.CALL_BACKS) {
|
||||
callBack.executor();
|
||||
}
|
||||
CALL_BACKS.clear();
|
||||
}
|
||||
SpringContextHolder.addCallback = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 @Service 的所有 bean 名称
|
||||
* @return /
|
||||
*/
|
||||
public static List<String> getAllServiceBeanName() {
|
||||
return new ArrayList<>(Arrays.asList(applicationContext
|
||||
.getBeanNamesForAnnotation(Service.class)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.config.ElAdminProperties;
|
||||
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
|
||||
import net.dreamlu.mica.ip2region.core.IpInfo;
|
||||
import nl.basjes.parse.useragent.UserAgent;
|
||||
import nl.basjes.parse.useragent.UserAgentAnalyzer;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
|
||||
*/
|
||||
@Slf4j
|
||||
public class StringUtils extends org.apache.commons.lang3.StringUtils {
|
||||
|
||||
private static final char SEPARATOR = '_';
|
||||
private static final String UNKNOWN = "unknown";
|
||||
|
||||
/**
|
||||
* 注入bean
|
||||
*/
|
||||
private final static Ip2regionSearcher IP_SEARCHER = SpringContextHolder.getBean(Ip2regionSearcher.class);
|
||||
|
||||
|
||||
private static final UserAgentAnalyzer USER_AGENT_ANALYZER = UserAgentAnalyzer
|
||||
.newBuilder()
|
||||
.hideMatcherLoadStats()
|
||||
.withCache(10000)
|
||||
.withField(UserAgent.AGENT_NAME_VERSION)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* 驼峰命名法工具
|
||||
*
|
||||
* @return toCamelCase(" hello_world ") == "helloWorld"
|
||||
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
|
||||
* toUnderScoreCase("helloWorld") = "hello_world"
|
||||
*/
|
||||
public static String toCamelCase(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
s = s.toLowerCase();
|
||||
|
||||
StringBuilder sb = new StringBuilder(s.length());
|
||||
boolean upperCase = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
if (c == SEPARATOR) {
|
||||
upperCase = true;
|
||||
} else if (upperCase) {
|
||||
sb.append(Character.toUpperCase(c));
|
||||
upperCase = false;
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名法工具
|
||||
*
|
||||
* @return toCamelCase(" hello_world ") == "helloWorld"
|
||||
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
|
||||
* toUnderScoreCase("helloWorld") = "hello_world"
|
||||
*/
|
||||
public static String toCapitalizeCamelCase(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
s = toCamelCase(s);
|
||||
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名法工具
|
||||
*
|
||||
* @return toCamelCase(" hello_world ") == "helloWorld"
|
||||
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
|
||||
* toUnderScoreCase("helloWorld") = "hello_world"
|
||||
*/
|
||||
static String toUnderScoreCase(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean upperCase = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
boolean nextUpperCase = true;
|
||||
|
||||
if (i < (s.length() - 1)) {
|
||||
nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
|
||||
}
|
||||
|
||||
if ((i > 0) && Character.isUpperCase(c)) {
|
||||
if (!upperCase || !nextUpperCase) {
|
||||
sb.append(SEPARATOR);
|
||||
}
|
||||
upperCase = true;
|
||||
} else {
|
||||
upperCase = false;
|
||||
}
|
||||
|
||||
sb.append(Character.toLowerCase(c));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ip地址
|
||||
*/
|
||||
public static String getIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("x-forwarded-for");
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
String comma = ",";
|
||||
String localhost = "127.0.0.1";
|
||||
if (ip.contains(comma)) {
|
||||
ip = ip.split(",")[0];
|
||||
}
|
||||
if (localhost.equals(ip)) {
|
||||
// 获取本机真正的ip地址
|
||||
try {
|
||||
ip = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ip获取详细地址
|
||||
*/
|
||||
public static String getCityInfo(String ip) {
|
||||
if (ElAdminProperties.ipLocal) {
|
||||
return getLocalCityInfo(ip);
|
||||
} else {
|
||||
return getHttpCityInfo(ip);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ip获取详细地址
|
||||
*/
|
||||
public static String getHttpCityInfo(String ip) {
|
||||
String api = String.format(ElAdminConstant.Url.IP_URL, ip);
|
||||
JSONObject object = JSONUtil.parseObj(HttpUtil.get(api));
|
||||
return object.get("addr", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ip获取详细地址
|
||||
*/
|
||||
public static String getLocalCityInfo(String ip) {
|
||||
IpInfo ipInfo = IP_SEARCHER.memorySearch(ip);
|
||||
if(ipInfo != null){
|
||||
return ipInfo.getAddress();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public static String getBrowser(HttpServletRequest request) {
|
||||
UserAgent.ImmutableUserAgent userAgent = USER_AGENT_ANALYZER.parse(request.getHeader("User-Agent"));
|
||||
return userAgent.get(UserAgent.AGENT_NAME_VERSION).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当天是周几
|
||||
*/
|
||||
public static String getWeekDay() {
|
||||
String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(new Date());
|
||||
|
||||
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
if (w < 0) {
|
||||
w = 0;
|
||||
}
|
||||
return weekDays[w];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前机器的IP
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public static String getLocalIp() {
|
||||
try {
|
||||
InetAddress candidateAddress = null;
|
||||
// 遍历所有的网络接口
|
||||
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) {
|
||||
NetworkInterface anInterface = interfaces.nextElement();
|
||||
// 在所有的接口下再遍历IP
|
||||
for (Enumeration<InetAddress> inetAddresses = anInterface.getInetAddresses(); inetAddresses.hasMoreElements();) {
|
||||
InetAddress inetAddr = inetAddresses.nextElement();
|
||||
// 排除loopback类型地址
|
||||
if (!inetAddr.isLoopbackAddress()) {
|
||||
if (inetAddr.isSiteLocalAddress()) {
|
||||
// 如果是site-local地址,就是它了
|
||||
return inetAddr.getHostAddress();
|
||||
} else if (candidateAddress == null) {
|
||||
// site-local类型的地址未被发现,先记录候选地址
|
||||
candidateAddress = inetAddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (candidateAddress != null) {
|
||||
return candidateAddress.getHostAddress();
|
||||
}
|
||||
// 如果没有发现 non-loopback地址.只能用最次选的方案
|
||||
InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
|
||||
if (jdkSuppliedAddress == null) {
|
||||
return "";
|
||||
}
|
||||
return jdkSuppliedAddress.getHostAddress();
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* 异常工具 2019-01-06
|
||||
* @author Zheng Jie
|
||||
*/
|
||||
public class ThrowableUtil {
|
||||
|
||||
/**
|
||||
* 获取堆栈信息
|
||||
*/
|
||||
public static String getStackTrace(Throwable throwable){
|
||||
StringWriter sw = new StringWriter();
|
||||
try (PrintWriter pw = new PrintWriter(sw)) {
|
||||
throwable.printStackTrace(pw);
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* 翻译工具类
|
||||
*/
|
||||
public class TranslatorUtil {
|
||||
|
||||
public static String translate(String word){
|
||||
try {
|
||||
String url = "https://translate.googleapis.com/translate_a/single?" +
|
||||
"client=gtx&" +
|
||||
"sl=en" +
|
||||
"&tl=zh-CN" +
|
||||
"&dt=t&q=" + URLEncoder.encode(word, "UTF-8");
|
||||
|
||||
URL obj = new URL(url);
|
||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
||||
con.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuilder response = new StringBuilder();
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
return parseResult(response.toString());
|
||||
}catch (Exception e){
|
||||
return word;
|
||||
}
|
||||
}
|
||||
|
||||
private static String parseResult(String inputJson){
|
||||
JSONArray jsonArray2 = (JSONArray) new JSONArray(inputJson).get(0);
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (Object o : jsonArray2) {
|
||||
result.append(((JSONArray) o).get(0).toString());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
|
||||
/**
|
||||
* 验证工具
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public class ValidationUtil {
|
||||
|
||||
/**
|
||||
* 验证空
|
||||
*/
|
||||
public static void isNull(Object obj, String entity, String parameter , Object value){
|
||||
if(ObjectUtil.isNull(obj)){
|
||||
String msg = entity + " 不存在: "+ parameter +" is "+ value;
|
||||
throw new BadRequestException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否为邮箱
|
||||
*/
|
||||
public static boolean isEmail(String email) {
|
||||
return Validator.isEmail(email);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 验证码业务场景
|
||||
* </p>
|
||||
* @author Zheng Jie
|
||||
* @date 2020-05-02
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CodeBiEnum {
|
||||
|
||||
/* 旧邮箱修改邮箱 */
|
||||
ONE(1, "旧邮箱修改邮箱"),
|
||||
|
||||
/* 通过邮箱修改密码 */
|
||||
TWO(2, "通过邮箱修改密码");
|
||||
|
||||
private final Integer code;
|
||||
private final String description;
|
||||
|
||||
public static CodeBiEnum find(Integer code) {
|
||||
for (CodeBiEnum value : CodeBiEnum.values()) {
|
||||
if (value.getCode().equals(code)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 验证码业务场景对应的 Redis 中的 key
|
||||
* </p>
|
||||
* @author Zheng Jie
|
||||
* @date 2020-05-02
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CodeEnum {
|
||||
|
||||
/* 通过手机号码重置邮箱 */
|
||||
PHONE_RESET_EMAIL_CODE("phone_reset_email_code_", "通过手机号码重置邮箱"),
|
||||
|
||||
/* 通过旧邮箱重置邮箱 */
|
||||
EMAIL_RESET_EMAIL_CODE("email_reset_email_code_", "通过旧邮箱重置邮箱"),
|
||||
|
||||
/* 通过手机号码重置密码 */
|
||||
PHONE_RESET_PWD_CODE("phone_reset_pwd_code_", "通过手机号码重置密码"),
|
||||
|
||||
/* 通过邮箱重置密码 */
|
||||
EMAIL_RESET_PWD_CODE("email_reset_pwd_code_", "通过邮箱重置密码");
|
||||
|
||||
private final String key;
|
||||
private final String description;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 数据权限枚举
|
||||
* </p>
|
||||
* @author Zheng Jie
|
||||
* @date 2020-05-07
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DataScopeEnum {
|
||||
|
||||
/* 全部的数据权限 */
|
||||
ALL("全部", "全部的数据权限"),
|
||||
|
||||
/* 自己部门的数据权限 */
|
||||
THIS_LEVEL("本级", "自己部门的数据权限"),
|
||||
|
||||
/* 自定义的数据权限 */
|
||||
CUSTOMIZE("自定义", "自定义的数据权限");
|
||||
|
||||
private final String value;
|
||||
private final String description;
|
||||
|
||||
public static DataScopeEnum find(String val) {
|
||||
for (DataScopeEnum dataScopeEnum : DataScopeEnum.values()) {
|
||||
if (dataScopeEnum.getValue().equals(val)) {
|
||||
return dataScopeEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @website https://eladmin.vip
|
||||
* @description
|
||||
* @date 2020-06-10
|
||||
**/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RequestMethodEnum {
|
||||
|
||||
/**
|
||||
* 搜寻 @AnonymousGetMapping
|
||||
*/
|
||||
GET("GET"),
|
||||
|
||||
/**
|
||||
* 搜寻 @AnonymousPostMapping
|
||||
*/
|
||||
POST("POST"),
|
||||
|
||||
/**
|
||||
* 搜寻 @AnonymousPutMapping
|
||||
*/
|
||||
PUT("PUT"),
|
||||
|
||||
/**
|
||||
* 搜寻 @AnonymousPatchMapping
|
||||
*/
|
||||
PATCH("PATCH"),
|
||||
|
||||
/**
|
||||
* 搜寻 @AnonymousDeleteMapping
|
||||
*/
|
||||
DELETE("DELETE"),
|
||||
|
||||
/**
|
||||
* 否则就是所有 Request 接口都放行
|
||||
*/
|
||||
ALL("All");
|
||||
|
||||
/**
|
||||
* Request 类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
public static RequestMethodEnum find(String type) {
|
||||
for (RequestMethodEnum value : RequestMethodEnum.values()) {
|
||||
if (value.getType().equals(type)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return ALL;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package me.zhengjie.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
public class DateUtilsTest {
|
||||
@Test
|
||||
public void test1() {
|
||||
long l = System.currentTimeMillis() / 1000;
|
||||
LocalDateTime localDateTime = DateUtil.fromTimeStamp(l);
|
||||
System.out.print(DateUtil.localDateTimeFormatyMdHms(localDateTime));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
System.out.println(DateUtil.localDateTimeFormatyMdHms(now));
|
||||
Date date = DateUtil.toDate(now);
|
||||
LocalDateTime localDateTime = DateUtil.toLocalDateTime(date);
|
||||
System.out.println(DateUtil.localDateTimeFormatyMdHms(localDateTime));
|
||||
LocalDateTime localDateTime1 = DateUtil.fromTimeStamp(date.getTime() / 1000);
|
||||
System.out.println(DateUtil.localDateTimeFormatyMdHms(localDateTime1));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package me.zhengjie.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static me.zhengjie.utils.EncryptUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class EncryptUtilsTest {
|
||||
|
||||
/**
|
||||
* 对称加密
|
||||
*/
|
||||
@Test
|
||||
public void testDesEncrypt() {
|
||||
try {
|
||||
assertEquals("7772841DC6099402", desEncrypt("123456"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对称解密
|
||||
*/
|
||||
@Test
|
||||
public void testDesDecrypt() {
|
||||
try {
|
||||
assertEquals("123456", desDecrypt("7772841DC6099402"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package me.zhengjie.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import static me.zhengjie.utils.FileUtil.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class FileUtilTest {
|
||||
|
||||
@Test
|
||||
public void testToFile() {
|
||||
long retval = toFile(new MockMultipartFile("foo", (byte[]) null)).getTotalSpace();
|
||||
assertEquals(500695072768L, retval);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExtensionName() {
|
||||
assertEquals("foo", getExtensionName("foo"));
|
||||
assertEquals("exe", getExtensionName("bar.exe"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFileNameNoEx() {
|
||||
assertEquals("foo", getFileNameNoEx("foo"));
|
||||
assertEquals("bar", getFileNameNoEx("bar.txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSize() {
|
||||
assertEquals("1000B ", getSize(1000));
|
||||
assertEquals("1.00KB ", getSize(1024));
|
||||
assertEquals("1.00MB ", getSize(1048576));
|
||||
assertEquals("1.00GB ", getSize(1073741824));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package me.zhengjie.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import static me.zhengjie.utils.StringUtils.getIp;
|
||||
import static me.zhengjie.utils.StringUtils.getWeekDay;
|
||||
import static me.zhengjie.utils.StringUtils.toCamelCase;
|
||||
import static me.zhengjie.utils.StringUtils.toCapitalizeCamelCase;
|
||||
import static me.zhengjie.utils.StringUtils.toUnderScoreCase;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class StringUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testToCamelCase() {
|
||||
assertNull(toCamelCase(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToCapitalizeCamelCase() {
|
||||
assertNull(StringUtils.toCapitalizeCamelCase(null));
|
||||
assertEquals("HelloWorld", toCapitalizeCamelCase("hello_world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToUnderScoreCase() {
|
||||
assertNull(StringUtils.toUnderScoreCase(null));
|
||||
assertEquals("hello_world", toUnderScoreCase("helloWorld"));
|
||||
assertEquals("\u0000\u0000", toUnderScoreCase("\u0000\u0000"));
|
||||
assertEquals("\u0000_a", toUnderScoreCase("\u0000A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetWeekDay() {
|
||||
SimpleDateFormat simpleDateformat = new SimpleDateFormat("E");
|
||||
assertEquals(simpleDateformat.format(new Date()), getWeekDay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIP() {
|
||||
assertEquals("127.0.0.1", getIp(new MockHttpServletRequest()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?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>eladmin</artifactId>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<version>2.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>eladmin-generator</artifactId>
|
||||
<name>代码生成模块</name>
|
||||
|
||||
<properties>
|
||||
<configuration.version>1.10</configuration.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<artifactId>eladmin-common</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
|
||||
<!--模板引擎-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/commons-configuration/commons-configuration -->
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<version>${configuration.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import me.zhengjie.utils.GenUtil;
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 列的数据信息
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@Table(name = "code_column_config")
|
||||
public class ColumnInfo implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "column_id")
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "表名")
|
||||
private String tableName;
|
||||
|
||||
@ApiModelProperty(value = "数据库字段名称")
|
||||
private String columnName;
|
||||
|
||||
@ApiModelProperty(value = "数据库字段类型")
|
||||
private String columnType;
|
||||
|
||||
@ApiModelProperty(value = "数据库字段键类型")
|
||||
private String keyType;
|
||||
|
||||
@ApiModelProperty(value = "字段额外的参数")
|
||||
private String extra;
|
||||
|
||||
@ApiModelProperty(value = "数据库字段描述")
|
||||
private String remark;
|
||||
|
||||
@ApiModelProperty(value = "是否必填")
|
||||
private Boolean notNull;
|
||||
|
||||
@ApiModelProperty(value = "是否在列表显示")
|
||||
private Boolean listShow;
|
||||
|
||||
@ApiModelProperty(value = "是否表单显示")
|
||||
private Boolean formShow;
|
||||
|
||||
@ApiModelProperty(value = "表单类型")
|
||||
private String formType;
|
||||
|
||||
@ApiModelProperty(value = "查询 1:模糊 2:精确")
|
||||
private String queryType;
|
||||
|
||||
@ApiModelProperty(value = "字典名称")
|
||||
private String dictName;
|
||||
|
||||
@ApiModelProperty(value = "日期注解")
|
||||
private String dateAnnotation;
|
||||
|
||||
public ColumnInfo(String tableName, String columnName, Boolean notNull, String columnType, String remark, String keyType, String extra) {
|
||||
this.tableName = tableName;
|
||||
this.columnName = columnName;
|
||||
this.columnType = columnType;
|
||||
this.keyType = keyType;
|
||||
this.extra = extra;
|
||||
this.notNull = notNull;
|
||||
if(GenUtil.PK.equalsIgnoreCase(keyType) && GenUtil.EXTRA.equalsIgnoreCase(extra)){
|
||||
this.notNull = false;
|
||||
}
|
||||
this.remark = remark;
|
||||
this.listShow = true;
|
||||
this.formShow = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 代码生成配置
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-03
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@Table(name = "code_gen_config")
|
||||
public class GenConfig implements Serializable {
|
||||
|
||||
public GenConfig(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "config_id")
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "表名")
|
||||
private String tableName;
|
||||
|
||||
@ApiModelProperty(value = "接口名称")
|
||||
private String apiAlias;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "包路径")
|
||||
private String pack;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "模块名")
|
||||
private String moduleName;
|
||||
|
||||
@NotBlank
|
||||
@ApiModelProperty(value = "前端文件路径")
|
||||
private String path;
|
||||
|
||||
@ApiModelProperty(value = "前端文件路径")
|
||||
private String apiPath;
|
||||
|
||||
@ApiModelProperty(value = "作者")
|
||||
private String author;
|
||||
|
||||
@ApiModelProperty(value = "表前缀")
|
||||
private String prefix;
|
||||
|
||||
@ApiModelProperty(value = "是否覆盖")
|
||||
private Boolean cover = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.domain.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 表的数据信息
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-02
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TableInfo {
|
||||
|
||||
/** 表名称 */
|
||||
private Object tableName;
|
||||
|
||||
/** 创建日期 */
|
||||
private Object createTime;
|
||||
|
||||
/** 数据库引擎 */
|
||||
private Object engine;
|
||||
|
||||
/** 编码集 */
|
||||
private Object coding;
|
||||
|
||||
/** 备注 */
|
||||
private Object remark;
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.repository;
|
||||
|
||||
import me.zhengjie.domain.ColumnInfo;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-14
|
||||
*/
|
||||
public interface ColumnInfoRepository extends JpaRepository<ColumnInfo,Long> {
|
||||
|
||||
/**
|
||||
* 查询表信息
|
||||
* @param tableName 表格名
|
||||
* @return 表信息
|
||||
*/
|
||||
List<ColumnInfo> findByTableNameOrderByIdAsc(String tableName);
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.repository;
|
||||
|
||||
import me.zhengjie.domain.GenConfig;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-14
|
||||
*/
|
||||
public interface GenConfigRepository extends JpaRepository<GenConfig,Long> {
|
||||
|
||||
/**
|
||||
* 查询表配置
|
||||
* @param tableName 表名
|
||||
* @return /
|
||||
*/
|
||||
GenConfig findByTableName(String tableName);
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.rest;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.domain.GenConfig;
|
||||
import me.zhengjie.service.GenConfigService;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-14
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/genConfig")
|
||||
@Api(tags = "系统:代码生成器配置管理")
|
||||
public class GenConfigController {
|
||||
|
||||
private final GenConfigService genConfigService;
|
||||
|
||||
@ApiOperation("查询")
|
||||
@GetMapping(value = "/{tableName}")
|
||||
public ResponseEntity<Object> queryGenConfig(@PathVariable String tableName){
|
||||
return new ResponseEntity<>(genConfigService.find(tableName), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@ApiOperation("修改")
|
||||
public ResponseEntity<Object> updateGenConfig(@Validated @RequestBody GenConfig genConfig){
|
||||
return new ResponseEntity<>(genConfigService.update(genConfig.getTableName(), genConfig),HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.rest;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.domain.ColumnInfo;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.service.GenConfigService;
|
||||
import me.zhengjie.service.GeneratorService;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-02
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/generator")
|
||||
@Api(tags = "系统:代码生成管理")
|
||||
public class GeneratorController {
|
||||
|
||||
private final GeneratorService generatorService;
|
||||
private final GenConfigService genConfigService;
|
||||
|
||||
@Value("${generator.enabled}")
|
||||
private Boolean generatorEnabled;
|
||||
|
||||
@ApiOperation("查询数据库数据")
|
||||
@GetMapping(value = "/tables/all")
|
||||
public ResponseEntity<Object> queryAllTables(){
|
||||
return new ResponseEntity<>(generatorService.getTables(), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@ApiOperation("查询数据库数据")
|
||||
@GetMapping(value = "/tables")
|
||||
public ResponseEntity<Object> queryTables(@RequestParam(defaultValue = "") String name,
|
||||
@RequestParam(defaultValue = "0")Integer page,
|
||||
@RequestParam(defaultValue = "10")Integer size){
|
||||
int[] startEnd = PageUtil.transToStartEnd(page, size);
|
||||
return new ResponseEntity<>(generatorService.getTables(name,startEnd), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@ApiOperation("查询字段数据")
|
||||
@GetMapping(value = "/columns")
|
||||
public ResponseEntity<Object> queryColumns(@RequestParam String tableName){
|
||||
List<ColumnInfo> columnInfos = generatorService.getColumns(tableName);
|
||||
return new ResponseEntity<>(PageUtil.toPage(columnInfos,columnInfos.size()), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@ApiOperation("保存字段数据")
|
||||
@PutMapping
|
||||
public ResponseEntity<HttpStatus> saveColumn(@RequestBody List<ColumnInfo> columnInfos){
|
||||
generatorService.save(columnInfos);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@ApiOperation("同步字段数据")
|
||||
@PostMapping(value = "sync")
|
||||
public ResponseEntity<HttpStatus> syncColumn(@RequestBody List<String> tables){
|
||||
for (String table : tables) {
|
||||
generatorService.sync(generatorService.getColumns(table), generatorService.query(table));
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@ApiOperation("生成代码")
|
||||
@PostMapping(value = "/{tableName}/{type}")
|
||||
public ResponseEntity<Object> generatorCode(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response){
|
||||
if(!generatorEnabled && type == 0){
|
||||
throw new BadRequestException("此环境不允许生成代码,请选择预览或者下载查看!");
|
||||
}
|
||||
switch (type){
|
||||
// 生成代码
|
||||
case 0: generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName));
|
||||
break;
|
||||
// 预览
|
||||
case 1: return generatorService.preview(genConfigService.find(tableName), generatorService.getColumns(tableName));
|
||||
// 打包
|
||||
case 2: generatorService.download(genConfigService.find(tableName), generatorService.getColumns(tableName), request, response);
|
||||
break;
|
||||
default: throw new BadRequestException("没有这个选项");
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service;
|
||||
|
||||
import me.zhengjie.domain.GenConfig;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-14
|
||||
*/
|
||||
public interface GenConfigService {
|
||||
|
||||
/**
|
||||
* 查询表配置
|
||||
* @param tableName 表名
|
||||
* @return 表配置
|
||||
*/
|
||||
GenConfig find(String tableName);
|
||||
|
||||
/**
|
||||
* 更新表配置
|
||||
* @param tableName 表名
|
||||
* @param genConfig 表配置
|
||||
* @return 表配置
|
||||
*/
|
||||
GenConfig update(String tableName, GenConfig genConfig);
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service;
|
||||
|
||||
import me.zhengjie.domain.GenConfig;
|
||||
import me.zhengjie.domain.ColumnInfo;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-02
|
||||
*/
|
||||
public interface GeneratorService {
|
||||
|
||||
/**
|
||||
* 查询数据库元数据
|
||||
* @param name 表名
|
||||
* @param startEnd 分页参数
|
||||
* @return /
|
||||
*/
|
||||
Object getTables(String name, int[] startEnd);
|
||||
|
||||
/**
|
||||
* 得到数据表的元数据
|
||||
* @param name 表名
|
||||
* @return /
|
||||
*/
|
||||
List<ColumnInfo> getColumns(String name);
|
||||
|
||||
/**
|
||||
* 同步表数据
|
||||
* @param columnInfos /
|
||||
* @param columnInfoList /
|
||||
*/
|
||||
void sync(List<ColumnInfo> columnInfos, List<ColumnInfo> columnInfoList);
|
||||
|
||||
/**
|
||||
* 保持数据
|
||||
* @param columnInfos /
|
||||
*/
|
||||
void save(List<ColumnInfo> columnInfos);
|
||||
|
||||
/**
|
||||
* 获取所有table
|
||||
* @return /
|
||||
*/
|
||||
Object getTables();
|
||||
|
||||
/**
|
||||
* 代码生成
|
||||
* @param genConfig 配置信息
|
||||
* @param columns 字段信息
|
||||
*/
|
||||
void generator(GenConfig genConfig, List<ColumnInfo> columns);
|
||||
|
||||
/**
|
||||
* 预览
|
||||
* @param genConfig 配置信息
|
||||
* @param columns 字段信息
|
||||
* @return /
|
||||
*/
|
||||
ResponseEntity<Object> preview(GenConfig genConfig, List<ColumnInfo> columns);
|
||||
|
||||
/**
|
||||
* 打包下载
|
||||
* @param genConfig 配置信息
|
||||
* @param columns 字段信息
|
||||
* @param request /
|
||||
* @param response /
|
||||
*/
|
||||
void download(GenConfig genConfig, List<ColumnInfo> columns, HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 查询数据库的表字段数据数据
|
||||
* @param table /
|
||||
* @return /
|
||||
*/
|
||||
List<ColumnInfo> query(String table);
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.domain.GenConfig;
|
||||
import me.zhengjie.repository.GenConfigRepository;
|
||||
import me.zhengjie.service.GenConfigService;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-14
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GenConfigServiceImpl implements GenConfigService {
|
||||
|
||||
private final GenConfigRepository genConfigRepository;
|
||||
|
||||
@Override
|
||||
public GenConfig find(String tableName) {
|
||||
GenConfig genConfig = genConfigRepository.findByTableName(tableName);
|
||||
if(genConfig == null){
|
||||
return new GenConfig(tableName);
|
||||
}
|
||||
return genConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenConfig update(String tableName, GenConfig genConfig) {
|
||||
String separator = File.separator;
|
||||
String[] paths;
|
||||
String symbol = "\\";
|
||||
if (symbol.equals(separator)) {
|
||||
paths = genConfig.getPath().split("\\\\");
|
||||
} else {
|
||||
paths = genConfig.getPath().split(File.separator);
|
||||
}
|
||||
StringBuilder api = new StringBuilder();
|
||||
for (String path : paths) {
|
||||
api.append(path);
|
||||
api.append(separator);
|
||||
if ("src".equals(path)) {
|
||||
api.append("api");
|
||||
break;
|
||||
}
|
||||
}
|
||||
genConfig.setApiPath(api.toString());
|
||||
return genConfigRepository.save(genConfig);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ZipUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.domain.GenConfig;
|
||||
import me.zhengjie.domain.ColumnInfo;
|
||||
import me.zhengjie.domain.vo.TableInfo;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.repository.ColumnInfoRepository;
|
||||
import me.zhengjie.service.GeneratorService;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.GenUtil;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.Query;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-02
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GeneratorServiceImpl implements GeneratorService {
|
||||
private static final Logger log = LoggerFactory.getLogger(GeneratorServiceImpl.class);
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
private final ColumnInfoRepository columnInfoRepository;
|
||||
|
||||
private final String CONFIG_MESSAGE = "请先配置生成器";
|
||||
@Override
|
||||
public Object getTables() {
|
||||
// 使用预编译防止sql注入
|
||||
String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " +
|
||||
"where table_schema = (select database()) " +
|
||||
"order by create_time desc";
|
||||
Query query = em.createNativeQuery(sql);
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTables(String name, int[] startEnd) {
|
||||
// 使用预编译防止sql注入
|
||||
String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " +
|
||||
"where table_schema = (select database()) " +
|
||||
"and table_name like :table order by create_time desc";
|
||||
Query query = em.createNativeQuery(sql);
|
||||
query.setFirstResult(startEnd[0]);
|
||||
query.setMaxResults(startEnd[1] - startEnd[0]);
|
||||
query.setParameter("table", StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
|
||||
List result = query.getResultList();
|
||||
List<TableInfo> tableInfos = new ArrayList<>();
|
||||
for (Object obj : result) {
|
||||
Object[] arr = (Object[]) obj;
|
||||
tableInfos.add(new TableInfo(arr[0], arr[1], arr[2], arr[3], ObjectUtil.isNotEmpty(arr[4]) ? arr[4] : "-"));
|
||||
}
|
||||
String countSql = "select count(1) from information_schema.tables " +
|
||||
"where table_schema = (select database()) and table_name like :table";
|
||||
Query queryCount = em.createNativeQuery(countSql);
|
||||
queryCount.setParameter("table", StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
|
||||
Object totalElements = queryCount.getSingleResult();
|
||||
return PageUtil.toPage(tableInfos, totalElements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnInfo> getColumns(String tableName) {
|
||||
List<ColumnInfo> columnInfos = columnInfoRepository.findByTableNameOrderByIdAsc(tableName);
|
||||
if (CollectionUtil.isNotEmpty(columnInfos)) {
|
||||
return columnInfos;
|
||||
} else {
|
||||
columnInfos = query(tableName);
|
||||
return columnInfoRepository.saveAll(columnInfos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnInfo> query(String tableName) {
|
||||
// 使用预编译防止sql注入
|
||||
String sql = "select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns " +
|
||||
"where table_name = ? and table_schema = (select database()) order by ordinal_position";
|
||||
Query query = em.createNativeQuery(sql);
|
||||
query.setParameter(1, tableName);
|
||||
List result = query.getResultList();
|
||||
List<ColumnInfo> columnInfos = new ArrayList<>();
|
||||
for (Object obj : result) {
|
||||
Object[] arr = (Object[]) obj;
|
||||
columnInfos.add(
|
||||
new ColumnInfo(
|
||||
tableName,
|
||||
arr[0].toString(),
|
||||
"NO".equals(arr[1]),
|
||||
arr[2].toString(),
|
||||
ObjectUtil.isNotNull(arr[3]) ? arr[3].toString() : null,
|
||||
ObjectUtil.isNotNull(arr[4]) ? arr[4].toString() : null,
|
||||
ObjectUtil.isNotNull(arr[5]) ? arr[5].toString() : null)
|
||||
);
|
||||
}
|
||||
return columnInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sync(List<ColumnInfo> columnInfos, List<ColumnInfo> columnInfoList) {
|
||||
// 第一种情况,数据库类字段改变或者新增字段
|
||||
for (ColumnInfo columnInfo : columnInfoList) {
|
||||
// 根据字段名称查找
|
||||
List<ColumnInfo> columns = columnInfos.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
|
||||
// 如果能找到,就修改部分可能被字段
|
||||
if (CollectionUtil.isNotEmpty(columns)) {
|
||||
ColumnInfo column = columns.get(0);
|
||||
column.setColumnType(columnInfo.getColumnType());
|
||||
column.setExtra(columnInfo.getExtra());
|
||||
column.setKeyType(columnInfo.getKeyType());
|
||||
if (StringUtils.isBlank(column.getRemark())) {
|
||||
column.setRemark(columnInfo.getRemark());
|
||||
}
|
||||
columnInfoRepository.save(column);
|
||||
} else {
|
||||
// 如果找不到,则保存新字段信息
|
||||
columnInfoRepository.save(columnInfo);
|
||||
}
|
||||
}
|
||||
// 第二种情况,数据库字段删除了
|
||||
for (ColumnInfo columnInfo : columnInfos) {
|
||||
// 根据字段名称查找
|
||||
List<ColumnInfo> columns = columnInfoList.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
|
||||
// 如果找不到,就代表字段被删除了,则需要删除该字段
|
||||
if (CollectionUtil.isEmpty(columns)) {
|
||||
columnInfoRepository.delete(columnInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(List<ColumnInfo> columnInfos) {
|
||||
columnInfoRepository.saveAll(columnInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generator(GenConfig genConfig, List<ColumnInfo> columns) {
|
||||
if (genConfig.getId() == null) {
|
||||
throw new BadRequestException(CONFIG_MESSAGE);
|
||||
}
|
||||
try {
|
||||
GenUtil.generatorCode(columns, genConfig);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new BadRequestException("生成失败,请手动处理已生成的文件");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<Object> preview(GenConfig genConfig, List<ColumnInfo> columns) {
|
||||
if (genConfig.getId() == null) {
|
||||
throw new BadRequestException(CONFIG_MESSAGE);
|
||||
}
|
||||
List<Map<String, Object>> genList = GenUtil.preview(columns, genConfig);
|
||||
return new ResponseEntity<>(genList, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(GenConfig genConfig, List<ColumnInfo> columns, HttpServletRequest request, HttpServletResponse response) {
|
||||
if (genConfig.getId() == null) {
|
||||
throw new BadRequestException(CONFIG_MESSAGE);
|
||||
}
|
||||
try {
|
||||
File file = new File(GenUtil.download(columns, genConfig));
|
||||
String zipPath = file.getPath() + ".zip";
|
||||
ZipUtil.zip(file.getPath(), zipPath);
|
||||
FileUtil.downloadFile(request, response, new File(zipPath), true);
|
||||
} catch (IOException e) {
|
||||
throw new BadRequestException("打包失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import org.apache.commons.configuration.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* sql字段转java
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-03
|
||||
*/
|
||||
public class ColUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(ColUtil.class);
|
||||
|
||||
/**
|
||||
* 转换mysql数据类型为java数据类型
|
||||
*
|
||||
* @param type 数据库字段类型
|
||||
* @return String
|
||||
*/
|
||||
static String cloToJava(String type) {
|
||||
Configuration config = getConfig();
|
||||
assert config != null;
|
||||
return config.getString(type, "unknowType");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置信息
|
||||
*/
|
||||
public static PropertiesConfiguration getConfig() {
|
||||
try {
|
||||
return new PropertiesConfiguration("generator.properties");
|
||||
} catch (ConfigurationException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.template.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.domain.GenConfig;
|
||||
import me.zhengjie.domain.ColumnInfo;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
|
||||
import static me.zhengjie.utils.FileUtil.SYS_TEM_DIR;
|
||||
|
||||
/**
|
||||
* 代码生成
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-02
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings({"unchecked", "all"})
|
||||
public class GenUtil {
|
||||
|
||||
private static final String TIMESTAMP = "Timestamp";
|
||||
|
||||
private static final String BIGDECIMAL = "BigDecimal";
|
||||
|
||||
public static final String PK = "PRI";
|
||||
|
||||
public static final String EXTRA = "auto_increment";
|
||||
|
||||
/**
|
||||
* 获取后端代码模板名称
|
||||
*
|
||||
* @return List
|
||||
*/
|
||||
private static List<String> getAdminTemplateNames() {
|
||||
List<String> templateNames = new ArrayList<>();
|
||||
templateNames.add("Entity");
|
||||
templateNames.add("Dto");
|
||||
templateNames.add("Mapper");
|
||||
templateNames.add("Controller");
|
||||
templateNames.add("QueryCriteria");
|
||||
templateNames.add("Service");
|
||||
templateNames.add("ServiceImpl");
|
||||
templateNames.add("Repository");
|
||||
return templateNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取前端代码模板名称
|
||||
*
|
||||
* @return List
|
||||
*/
|
||||
private static List<String> getFrontTemplateNames() {
|
||||
List<String> templateNames = new ArrayList<>();
|
||||
templateNames.add("index");
|
||||
templateNames.add("api");
|
||||
return templateNames;
|
||||
}
|
||||
|
||||
public static List<Map<String, Object>> preview(List<ColumnInfo> columns, GenConfig genConfig) {
|
||||
Map<String, Object> genMap = getGenMap(columns, genConfig);
|
||||
List<Map<String, Object>> genList = new ArrayList<>();
|
||||
// 获取后端模版
|
||||
List<String> templates = getAdminTemplateNames();
|
||||
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
|
||||
for (String templateName : templates) {
|
||||
Map<String, Object> map = new HashMap<>(1);
|
||||
Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
|
||||
map.put("content", template.render(genMap));
|
||||
map.put("name", templateName);
|
||||
genList.add(map);
|
||||
}
|
||||
// 获取前端模版
|
||||
templates = getFrontTemplateNames();
|
||||
for (String templateName : templates) {
|
||||
Map<String, Object> map = new HashMap<>(1);
|
||||
Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
|
||||
map.put(templateName, template.render(genMap));
|
||||
map.put("content", template.render(genMap));
|
||||
map.put("name", templateName);
|
||||
genList.add(map);
|
||||
}
|
||||
return genList;
|
||||
}
|
||||
|
||||
public static String download(List<ColumnInfo> columns, GenConfig genConfig) throws IOException {
|
||||
// 拼接的路径:/tmpeladmin-gen-temp/,这个路径在Linux下需要root用户才有权限创建,非root用户会权限错误而失败,更改为: /tmp/eladmin-gen-temp/
|
||||
// String tempPath =SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator;
|
||||
String tempPath = SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator;
|
||||
Map<String, Object> genMap = getGenMap(columns, genConfig);
|
||||
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
|
||||
// 生成后端代码
|
||||
List<String> templates = getAdminTemplateNames();
|
||||
for (String templateName : templates) {
|
||||
Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
|
||||
String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), tempPath + "eladmin" + File.separator);
|
||||
assert filePath != null;
|
||||
File file = new File(filePath);
|
||||
// 如果非覆盖生成
|
||||
if (!genConfig.getCover() && FileUtil.exist(file)) {
|
||||
continue;
|
||||
}
|
||||
// 生成代码
|
||||
genFile(file, template, genMap);
|
||||
}
|
||||
// 生成前端代码
|
||||
templates = getFrontTemplateNames();
|
||||
for (String templateName : templates) {
|
||||
Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
|
||||
String path = tempPath + "eladmin-web" + File.separator;
|
||||
String apiPath = path + "src" + File.separator + "api" + File.separator;
|
||||
String srcPath = path + "src" + File.separator + "views" + File.separator + genMap.get("changeClassName").toString() + File.separator;
|
||||
String filePath = getFrontFilePath(templateName, apiPath, srcPath, genMap.get("changeClassName").toString());
|
||||
assert filePath != null;
|
||||
File file = new File(filePath);
|
||||
// 如果非覆盖生成
|
||||
if (!genConfig.getCover() && FileUtil.exist(file)) {
|
||||
continue;
|
||||
}
|
||||
// 生成代码
|
||||
genFile(file, template, genMap);
|
||||
}
|
||||
return tempPath;
|
||||
}
|
||||
|
||||
public static void generatorCode(List<ColumnInfo> columnInfos, GenConfig genConfig) throws IOException {
|
||||
Map<String, Object> genMap = getGenMap(columnInfos, genConfig);
|
||||
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
|
||||
// 生成后端代码
|
||||
List<String> templates = getAdminTemplateNames();
|
||||
for (String templateName : templates) {
|
||||
Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
|
||||
String rootPath = System.getProperty("user.dir");
|
||||
String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), rootPath);
|
||||
|
||||
assert filePath != null;
|
||||
File file = new File(filePath);
|
||||
|
||||
// 如果非覆盖生成
|
||||
if (!genConfig.getCover() && FileUtil.exist(file)) {
|
||||
continue;
|
||||
}
|
||||
// 生成代码
|
||||
genFile(file, template, genMap);
|
||||
}
|
||||
|
||||
// 生成前端代码
|
||||
templates = getFrontTemplateNames();
|
||||
for (String templateName : templates) {
|
||||
Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
|
||||
String filePath = getFrontFilePath(templateName, genConfig.getApiPath(), genConfig.getPath(), genMap.get("changeClassName").toString());
|
||||
|
||||
assert filePath != null;
|
||||
File file = new File(filePath);
|
||||
|
||||
// 如果非覆盖生成
|
||||
if (!genConfig.getCover() && FileUtil.exist(file)) {
|
||||
continue;
|
||||
}
|
||||
// 生成代码
|
||||
genFile(file, template, genMap);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取模版数据
|
||||
private static Map<String, Object> getGenMap(List<ColumnInfo> columnInfos, GenConfig genConfig) {
|
||||
// 存储模版字段数据
|
||||
Map<String, Object> genMap = new HashMap<>(16);
|
||||
// 接口别名
|
||||
genMap.put("apiAlias", genConfig.getApiAlias());
|
||||
// 包名称
|
||||
genMap.put("package", genConfig.getPack());
|
||||
// 模块名称
|
||||
genMap.put("moduleName", genConfig.getModuleName());
|
||||
// 作者
|
||||
genMap.put("author", genConfig.getAuthor());
|
||||
// 创建日期
|
||||
genMap.put("date", LocalDate.now().toString());
|
||||
// 表名
|
||||
genMap.put("tableName", genConfig.getTableName());
|
||||
// 大写开头的类名
|
||||
String className = StringUtils.toCapitalizeCamelCase(genConfig.getTableName());
|
||||
// 小写开头的类名
|
||||
String changeClassName = StringUtils.toCamelCase(genConfig.getTableName());
|
||||
// 判断是否去除表前缀
|
||||
if (StringUtils.isNotEmpty(genConfig.getPrefix())) {
|
||||
className = StringUtils.toCapitalizeCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix()));
|
||||
changeClassName = StringUtils.toCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix()));
|
||||
changeClassName = StringUtils.uncapitalize(changeClassName);
|
||||
}
|
||||
// 保存类名
|
||||
genMap.put("className", className);
|
||||
// 保存小写开头的类名
|
||||
genMap.put("changeClassName", changeClassName);
|
||||
// 存在 Timestamp 字段
|
||||
genMap.put("hasTimestamp", false);
|
||||
// 查询类中存在 Timestamp 字段
|
||||
genMap.put("queryHasTimestamp", false);
|
||||
// 存在 BigDecimal 字段
|
||||
genMap.put("hasBigDecimal", false);
|
||||
// 查询类中存在 BigDecimal 字段
|
||||
genMap.put("queryHasBigDecimal", false);
|
||||
// 是否需要创建查询
|
||||
genMap.put("hasQuery", false);
|
||||
// 自增主键
|
||||
genMap.put("auto", false);
|
||||
// 存在字典
|
||||
genMap.put("hasDict", false);
|
||||
// 存在日期注解
|
||||
genMap.put("hasDateAnnotation", false);
|
||||
// 保存字段信息
|
||||
List<Map<String, Object>> columns = new ArrayList<>();
|
||||
// 保存查询字段的信息
|
||||
List<Map<String, Object>> queryColumns = new ArrayList<>();
|
||||
// 存储字典信息
|
||||
List<String> dicts = new ArrayList<>();
|
||||
// 存储 between 信息
|
||||
List<Map<String, Object>> betweens = new ArrayList<>();
|
||||
// 存储不为空的字段信息
|
||||
List<Map<String, Object>> isNotNullColumns = new ArrayList<>();
|
||||
|
||||
for (ColumnInfo column : columnInfos) {
|
||||
Map<String, Object> listMap = new HashMap<>(16);
|
||||
// 字段描述
|
||||
listMap.put("remark", column.getRemark());
|
||||
// 字段类型
|
||||
listMap.put("columnKey", column.getKeyType());
|
||||
// 主键类型
|
||||
String colType = ColUtil.cloToJava(column.getColumnType());
|
||||
// 小写开头的字段名
|
||||
String changeColumnName = StringUtils.toCamelCase(column.getColumnName());
|
||||
// 大写开头的字段名
|
||||
String capitalColumnName = StringUtils.toCapitalizeCamelCase(column.getColumnName());
|
||||
if (PK.equals(column.getKeyType())) {
|
||||
// 存储主键类型
|
||||
genMap.put("pkColumnType", colType);
|
||||
// 存储小写开头的字段名
|
||||
genMap.put("pkChangeColName", changeColumnName);
|
||||
// 存储大写开头的字段名
|
||||
genMap.put("pkCapitalColName", capitalColumnName);
|
||||
}
|
||||
// 是否存在 Timestamp 类型的字段
|
||||
if (TIMESTAMP.equals(colType)) {
|
||||
genMap.put("hasTimestamp", true);
|
||||
}
|
||||
// 是否存在 BigDecimal 类型的字段
|
||||
if (BIGDECIMAL.equals(colType)) {
|
||||
genMap.put("hasBigDecimal", true);
|
||||
}
|
||||
// 主键是否自增
|
||||
if (EXTRA.equals(column.getExtra())) {
|
||||
genMap.put("auto", true);
|
||||
}
|
||||
// 主键存在字典
|
||||
if (StringUtils.isNotBlank(column.getDictName())) {
|
||||
genMap.put("hasDict", true);
|
||||
if(!dicts.contains(column.getDictName()))
|
||||
dicts.add(column.getDictName());
|
||||
}
|
||||
|
||||
// 存储字段类型
|
||||
listMap.put("columnType", colType);
|
||||
// 存储字原始段名称
|
||||
listMap.put("columnName", column.getColumnName());
|
||||
// 不为空
|
||||
listMap.put("istNotNull", column.getNotNull());
|
||||
// 字段列表显示
|
||||
listMap.put("columnShow", column.getListShow());
|
||||
// 表单显示
|
||||
listMap.put("formShow", column.getFormShow());
|
||||
// 表单组件类型
|
||||
listMap.put("formType", StringUtils.isNotBlank(column.getFormType()) ? column.getFormType() : "Input");
|
||||
// 小写开头的字段名称
|
||||
listMap.put("changeColumnName", changeColumnName);
|
||||
//大写开头的字段名称
|
||||
listMap.put("capitalColumnName", capitalColumnName);
|
||||
// 字典名称
|
||||
listMap.put("dictName", column.getDictName());
|
||||
// 日期注解
|
||||
listMap.put("dateAnnotation", column.getDateAnnotation());
|
||||
if (StringUtils.isNotBlank(column.getDateAnnotation())) {
|
||||
genMap.put("hasDateAnnotation", true);
|
||||
}
|
||||
// 添加非空字段信息
|
||||
if (column.getNotNull()) {
|
||||
isNotNullColumns.add(listMap);
|
||||
}
|
||||
// 判断是否有查询,如有则把查询的字段set进columnQuery
|
||||
if (!StringUtils.isBlank(column.getQueryType())) {
|
||||
// 查询类型
|
||||
listMap.put("queryType", column.getQueryType());
|
||||
// 是否存在查询
|
||||
genMap.put("hasQuery", true);
|
||||
if (TIMESTAMP.equals(colType)) {
|
||||
// 查询中存储 Timestamp 类型
|
||||
genMap.put("queryHasTimestamp", true);
|
||||
}
|
||||
if (BIGDECIMAL.equals(colType)) {
|
||||
// 查询中存储 BigDecimal 类型
|
||||
genMap.put("queryHasBigDecimal", true);
|
||||
}
|
||||
if ("between".equalsIgnoreCase(column.getQueryType())) {
|
||||
betweens.add(listMap);
|
||||
} else {
|
||||
// 添加到查询列表中
|
||||
queryColumns.add(listMap);
|
||||
}
|
||||
}
|
||||
// 添加到字段列表中
|
||||
columns.add(listMap);
|
||||
}
|
||||
// 保存字段列表
|
||||
genMap.put("columns", columns);
|
||||
// 保存查询列表
|
||||
genMap.put("queryColumns", queryColumns);
|
||||
// 保存字段列表
|
||||
genMap.put("dicts", dicts);
|
||||
// 保存查询列表
|
||||
genMap.put("betweens", betweens);
|
||||
// 保存非空字段信息
|
||||
genMap.put("isNotNullColumns", isNotNullColumns);
|
||||
return genMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义后端文件路径以及名称
|
||||
*/
|
||||
private static String getAdminFilePath(String templateName, GenConfig genConfig, String className, String rootPath) {
|
||||
String projectPath = rootPath + File.separator + genConfig.getModuleName();
|
||||
String packagePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
|
||||
if (!ObjectUtils.isEmpty(genConfig.getPack())) {
|
||||
packagePath += genConfig.getPack().replace(".", File.separator) + File.separator;
|
||||
}
|
||||
|
||||
if ("Entity".equals(templateName)) {
|
||||
return packagePath + "domain" + File.separator + className + ".java";
|
||||
}
|
||||
|
||||
if ("Controller".equals(templateName)) {
|
||||
return packagePath + "rest" + File.separator + className + "Controller.java";
|
||||
}
|
||||
|
||||
if ("Service".equals(templateName)) {
|
||||
return packagePath + "service" + File.separator + className + "Service.java";
|
||||
}
|
||||
|
||||
if ("ServiceImpl".equals(templateName)) {
|
||||
return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
|
||||
}
|
||||
|
||||
if ("Dto".equals(templateName)) {
|
||||
return packagePath + "service" + File.separator + "dto" + File.separator + className + "Dto.java";
|
||||
}
|
||||
|
||||
if ("QueryCriteria".equals(templateName)) {
|
||||
return packagePath + "service" + File.separator + "dto" + File.separator + className + "QueryCriteria.java";
|
||||
}
|
||||
|
||||
if ("Mapper".equals(templateName)) {
|
||||
return packagePath + "service" + File.separator + "mapstruct" + File.separator + className + "Mapper.java";
|
||||
}
|
||||
|
||||
if ("Repository".equals(templateName)) {
|
||||
return packagePath + "repository" + File.separator + className + "Repository.java";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义前端文件路径以及名称
|
||||
*/
|
||||
private static String getFrontFilePath(String templateName, String apiPath, String path, String apiName) {
|
||||
|
||||
if ("api".equals(templateName)) {
|
||||
return apiPath + File.separator + apiName + ".js";
|
||||
}
|
||||
|
||||
if ("index".equals(templateName)) {
|
||||
return path + File.separator + "index.vue";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void genFile(File file, Template template, Map<String, Object> map) throws IOException {
|
||||
// 生成目标文件
|
||||
Writer writer = null;
|
||||
try {
|
||||
FileUtil.touch(file);
|
||||
writer = new FileWriter(file);
|
||||
template.render(map, writer);
|
||||
} catch (TemplateException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
assert writer != null;
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?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>eladmin</artifactId>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<version>2.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>eladmin-logging</artifactId>
|
||||
<name>日志模块</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<artifactId>eladmin-common</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Log {
|
||||
String value() default "";
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.domain.Log;
|
||||
import me.zhengjie.service.LogService;
|
||||
import me.zhengjie.utils.RequestHolder;
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import me.zhengjie.utils.ThrowableUtil;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@Component
|
||||
@Aspect
|
||||
@Slf4j
|
||||
public class LogAspect {
|
||||
|
||||
private final LogService logService;
|
||||
|
||||
ThreadLocal<Long> currentTime = new ThreadLocal<>();
|
||||
|
||||
public LogAspect(LogService logService) {
|
||||
this.logService = logService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置切入点
|
||||
*/
|
||||
@Pointcut("@annotation(me.zhengjie.annotation.Log)")
|
||||
public void logPointcut() {
|
||||
// 该方法无方法体,主要为了让同类中其他方法使用此切入点
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置环绕通知,使用在方法logPointcut()上注册的切入点
|
||||
*
|
||||
* @param joinPoint join point for advice
|
||||
*/
|
||||
@Around("logPointcut()")
|
||||
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
Object result;
|
||||
currentTime.set(System.currentTimeMillis());
|
||||
result = joinPoint.proceed();
|
||||
Log log = new Log("INFO",System.currentTimeMillis() - currentTime.get());
|
||||
currentTime.remove();
|
||||
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||
logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置异常通知
|
||||
*
|
||||
* @param joinPoint join point for advice
|
||||
* @param e exception
|
||||
*/
|
||||
@AfterThrowing(pointcut = "logPointcut()", throwing = "e")
|
||||
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
|
||||
Log log = new Log("ERROR",System.currentTimeMillis() - currentTime.get());
|
||||
currentTime.remove();
|
||||
log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
|
||||
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||
logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
try {
|
||||
return SecurityUtils.getCurrentUsername();
|
||||
}catch (Exception e){
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Table(name = "sys_log")
|
||||
@NoArgsConstructor
|
||||
public class Log implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "log_id")
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/** 操作用户 */
|
||||
private String username;
|
||||
|
||||
/** 描述 */
|
||||
private String description;
|
||||
|
||||
/** 方法名 */
|
||||
private String method;
|
||||
|
||||
/** 参数 */
|
||||
private String params;
|
||||
|
||||
/** 日志类型 */
|
||||
private String logType;
|
||||
|
||||
/** 请求ip */
|
||||
private String requestIp;
|
||||
|
||||
/** 地址 */
|
||||
private String address;
|
||||
|
||||
/** 浏览器 */
|
||||
private String browser;
|
||||
|
||||
/** 请求耗时 */
|
||||
private Long time;
|
||||
|
||||
/** 异常详细 */
|
||||
private byte[] exceptionDetail;
|
||||
|
||||
/** 创建日期 */
|
||||
@CreationTimestamp
|
||||
private Timestamp createTime;
|
||||
|
||||
public Log(String logType, Long time) {
|
||||
this.logType = logType;
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.repository;
|
||||
|
||||
import me.zhengjie.domain.Log;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@Repository
|
||||
public interface LogRepository extends JpaRepository<Log,Long>, JpaSpecificationExecutor<Log> {
|
||||
|
||||
/**
|
||||
* 根据日志类型删除信息
|
||||
* @param logType 日志类型
|
||||
*/
|
||||
@Modifying
|
||||
@Query(value = "delete from sys_log where log_type = ?1", nativeQuery = true)
|
||||
void deleteByLogType(String logType);
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.rest;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.service.LogService;
|
||||
import me.zhengjie.service.dto.LogQueryCriteria;
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/logs")
|
||||
@Api(tags = "系统:日志管理")
|
||||
public class LogController {
|
||||
|
||||
private final LogService logService;
|
||||
|
||||
@Log("导出数据")
|
||||
@ApiOperation("导出数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check()")
|
||||
public void exportLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException {
|
||||
criteria.setLogType("INFO");
|
||||
logService.download(logService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@Log("导出错误数据")
|
||||
@ApiOperation("导出错误数据")
|
||||
@GetMapping(value = "/error/download")
|
||||
@PreAuthorize("@el.check()")
|
||||
public void exportErrorLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException {
|
||||
criteria.setLogType("ERROR");
|
||||
logService.download(logService.queryAll(criteria), response);
|
||||
}
|
||||
@GetMapping
|
||||
@ApiOperation("日志查询")
|
||||
@PreAuthorize("@el.check()")
|
||||
public ResponseEntity<Object> queryLog(LogQueryCriteria criteria, Pageable pageable){
|
||||
criteria.setLogType("INFO");
|
||||
return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/user")
|
||||
@ApiOperation("用户日志查询")
|
||||
public ResponseEntity<Object> queryUserLog(LogQueryCriteria criteria, Pageable pageable){
|
||||
criteria.setLogType("INFO");
|
||||
criteria.setUsername(SecurityUtils.getCurrentUsername());
|
||||
return new ResponseEntity<>(logService.queryAllByUser(criteria,pageable), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/error")
|
||||
@ApiOperation("错误日志查询")
|
||||
@PreAuthorize("@el.check()")
|
||||
public ResponseEntity<Object> queryErrorLog(LogQueryCriteria criteria, Pageable pageable){
|
||||
criteria.setLogType("ERROR");
|
||||
return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/error/{id}")
|
||||
@ApiOperation("日志异常详情查询")
|
||||
@PreAuthorize("@el.check()")
|
||||
public ResponseEntity<Object> queryErrorLogDetail(@PathVariable Long id){
|
||||
return new ResponseEntity<>(logService.findByErrDetail(id), HttpStatus.OK);
|
||||
}
|
||||
@DeleteMapping(value = "/del/error")
|
||||
@Log("删除所有ERROR日志")
|
||||
@ApiOperation("删除所有ERROR日志")
|
||||
@PreAuthorize("@el.check()")
|
||||
public ResponseEntity<Object> delAllErrorLog(){
|
||||
logService.delAllByError();
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping(value = "/del/info")
|
||||
@Log("删除所有INFO日志")
|
||||
@ApiOperation("删除所有INFO日志")
|
||||
@PreAuthorize("@el.check()")
|
||||
public ResponseEntity<Object> delAllInfoLog(){
|
||||
logService.delAllByInfo();
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service;
|
||||
|
||||
import me.zhengjie.domain.Log;
|
||||
import me.zhengjie.service.dto.LogQueryCriteria;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
public interface LogService {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param criteria 查询条件
|
||||
* @param pageable 分页参数
|
||||
* @return /
|
||||
*/
|
||||
Object queryAll(LogQueryCriteria criteria, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
* @param criteria 查询条件
|
||||
* @return /
|
||||
*/
|
||||
List<Log> queryAll(LogQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 查询用户日志
|
||||
* @param criteria 查询条件
|
||||
* @param pageable 分页参数
|
||||
* @return -
|
||||
*/
|
||||
Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 保存日志数据
|
||||
* @param username 用户
|
||||
* @param browser 浏览器
|
||||
* @param ip 请求IP
|
||||
* @param joinPoint /
|
||||
* @param log 日志实体
|
||||
*/
|
||||
@Async
|
||||
void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log);
|
||||
|
||||
/**
|
||||
* 查询异常详情
|
||||
* @param id 日志ID
|
||||
* @return Object
|
||||
*/
|
||||
Object findByErrDetail(Long id);
|
||||
|
||||
/**
|
||||
* 导出日志
|
||||
* @param logs 待导出的数据
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<Log> logs, HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 删除所有错误日志
|
||||
*/
|
||||
void delAllByError();
|
||||
|
||||
/**
|
||||
* 删除所有INFO日志
|
||||
*/
|
||||
void delAllByInfo();
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-5-22
|
||||
*/
|
||||
@Data
|
||||
public class LogErrorDTO implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
private String description;
|
||||
|
||||
private String method;
|
||||
|
||||
private String params;
|
||||
|
||||
private String browser;
|
||||
|
||||
private String requestIp;
|
||||
|
||||
private String address;
|
||||
|
||||
private Timestamp createTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import me.zhengjie.annotation.Query;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 日志查询类
|
||||
* @author Zheng Jie
|
||||
* @date 2019-6-4 09:23:07
|
||||
*/
|
||||
@Data
|
||||
public class LogQueryCriteria {
|
||||
|
||||
@Query(blurry = "username,description,address,requestIp,method,params")
|
||||
private String blurry;
|
||||
|
||||
@Query
|
||||
private String username;
|
||||
|
||||
@Query
|
||||
private String logType;
|
||||
|
||||
@Query(type = Query.Type.BETWEEN)
|
||||
private List<Timestamp> createTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-5-22
|
||||
*/
|
||||
@Data
|
||||
public class LogSmallDTO implements Serializable {
|
||||
|
||||
private String description;
|
||||
|
||||
private String requestIp;
|
||||
|
||||
private Long time;
|
||||
|
||||
private String address;
|
||||
|
||||
private String browser;
|
||||
|
||||
private Timestamp createTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.domain.Log;
|
||||
import me.zhengjie.repository.LogRepository;
|
||||
import me.zhengjie.service.LogService;
|
||||
import me.zhengjie.service.dto.LogQueryCriteria;
|
||||
import me.zhengjie.service.mapstruct.LogErrorMapper;
|
||||
import me.zhengjie.service.mapstruct.LogSmallMapper;
|
||||
import me.zhengjie.utils.*;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LogServiceImpl implements LogService {
|
||||
private final LogRepository logRepository;
|
||||
private final LogErrorMapper logErrorMapper;
|
||||
private final LogSmallMapper logSmallMapper;
|
||||
|
||||
@Override
|
||||
public Object queryAll(LogQueryCriteria criteria, Pageable pageable) {
|
||||
Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable);
|
||||
String status = "ERROR";
|
||||
if (status.equals(criteria.getLogType())) {
|
||||
return PageUtil.toPage(page.map(logErrorMapper::toDto));
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Log> queryAll(LogQueryCriteria criteria) {
|
||||
return logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable) {
|
||||
Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable);
|
||||
return PageUtil.toPage(page.map(logSmallMapper::toDto));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log) {
|
||||
if (log == null) {
|
||||
throw new IllegalArgumentException("Log 不能为 null!");
|
||||
}
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
me.zhengjie.annotation.Log aopLog = method.getAnnotation(me.zhengjie.annotation.Log.class);
|
||||
|
||||
// 方法路径
|
||||
String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
|
||||
|
||||
// 描述
|
||||
log.setDescription(aopLog.value());
|
||||
|
||||
log.setRequestIp(ip);
|
||||
log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
|
||||
log.setMethod(methodName);
|
||||
log.setUsername(username);
|
||||
log.setParams(getParameter(method, joinPoint.getArgs()));
|
||||
// 记录登录用户,隐藏密码信息
|
||||
if(signature.getName().equals("login") && StringUtils.isNotEmpty(log.getParams())){
|
||||
JSONObject obj = JSONUtil.parseObj(log.getParams());
|
||||
log.setUsername(obj.getStr("username", ""));
|
||||
log.setParams(JSONUtil.toJsonStr(Dict.create().set("username", log.getUsername())));
|
||||
}
|
||||
log.setBrowser(browser);
|
||||
logRepository.save(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据方法和传入的参数获取请求参数
|
||||
*/
|
||||
private String getParameter(Method method, Object[] args) {
|
||||
List<Object> argList = new ArrayList<>();
|
||||
Parameter[] parameters = method.getParameters();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
//将RequestBody注解修饰的参数作为请求参数
|
||||
RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
|
||||
if (requestBody != null) {
|
||||
argList.add(args[i]);
|
||||
}
|
||||
//将RequestParam注解修饰的参数作为请求参数
|
||||
RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
|
||||
if (requestParam != null) {
|
||||
Map<String, Object> map = new HashMap<>(2);
|
||||
String key = parameters[i].getName();
|
||||
if (!StringUtils.isEmpty(requestParam.value())) {
|
||||
key = requestParam.value();
|
||||
}
|
||||
map.put(key, args[i]);
|
||||
argList.add(map);
|
||||
}
|
||||
}
|
||||
if (argList.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : JSONUtil.toJsonStr(argList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object findByErrDetail(Long id) {
|
||||
Log log = logRepository.findById(id).orElseGet(Log::new);
|
||||
ValidationUtil.isNull(log.getId(), "Log", "id", id);
|
||||
byte[] details = log.getExceptionDetail();
|
||||
return Dict.create().set("exception", new String(ObjectUtil.isNotNull(details) ? details : "".getBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<Log> logs, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Log log : logs) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("用户名", log.getUsername());
|
||||
map.put("IP", log.getRequestIp());
|
||||
map.put("IP来源", log.getAddress());
|
||||
map.put("描述", log.getDescription());
|
||||
map.put("浏览器", log.getBrowser());
|
||||
map.put("请求耗时/毫秒", log.getTime());
|
||||
map.put("异常详情", new String(ObjectUtil.isNotNull(log.getExceptionDetail()) ? log.getExceptionDetail() : "".getBytes()));
|
||||
map.put("创建日期", log.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delAllByError() {
|
||||
logRepository.deleteByLogType("ERROR");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delAllByInfo() {
|
||||
logRepository.deleteByLogType("INFO");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.mapstruct;
|
||||
|
||||
import me.zhengjie.base.BaseMapper;
|
||||
import me.zhengjie.domain.Log;
|
||||
import me.zhengjie.service.dto.LogErrorDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-5-22
|
||||
*/
|
||||
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface LogErrorMapper extends BaseMapper<LogErrorDTO, Log> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.service.mapstruct;
|
||||
|
||||
import me.zhengjie.base.BaseMapper;
|
||||
import me.zhengjie.domain.Log;
|
||||
import me.zhengjie.service.dto.LogSmallDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-5-22
|
||||
*/
|
||||
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface LogSmallMapper extends BaseMapper<LogSmallDTO, Log> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<?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>eladmin</artifactId>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<version>2.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>eladmin-system</artifactId>
|
||||
<name>核心模块</name>
|
||||
|
||||
<properties>
|
||||
<jjwt.version>0.11.2</jjwt.version>
|
||||
<!-- oshi监控需要指定jna版本, 问题详见 https://github.com/oshi/oshi/issues/1040 -->
|
||||
<jna.version>5.8.0</jna.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- 代码生成模块 -->
|
||||
<dependency>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<artifactId>eladmin-generator</artifactId>
|
||||
<version>2.6</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<artifactId>eladmin-common</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- tools 模块包含了 common 和 logging 模块 -->
|
||||
<dependency>
|
||||
<groupId>me.zhengjie</groupId>
|
||||
<artifactId>eladmin-tools</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring boot websocket -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- jwt -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- quartz -->
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- linux的管理 -->
|
||||
<dependency>
|
||||
<groupId>ch.ethz.ganymed</groupId>
|
||||
<artifactId>ganymed-ssh2</artifactId>
|
||||
<version>build210</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch</artifactId>
|
||||
<version>0.1.55</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 获取系统信息 -->
|
||||
<dependency>
|
||||
<groupId>com.github.oshi</groupId>
|
||||
<artifactId>oshi-core</artifactId>
|
||||
<version>6.1.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- 打包 -->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>*.properties</exclude>
|
||||
<exclude>*.yml</exclude>
|
||||
<exclude>*.xml</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assembly/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd
|
||||
">
|
||||
<id>release</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src/assembly</directory>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
<includes>
|
||||
<include>*.sh</include>
|
||||
<include>*.bat</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
<includes>
|
||||
<include>*.properties</include>
|
||||
<include>application.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
|
||||
<fileSet>
|
||||
<directory>src/main/resources/config</directory>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
<includes>
|
||||
<include>*.yml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
<dependencySets>
|
||||
<!-- 将scope为runtime的依赖包打包到lib目录下。 -->
|
||||
<dependencySet>
|
||||
<useProjectArtifact>true</useProjectArtifact>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
<scope>runtime</scope>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
|
||||
</assembly>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@echo off
|
||||
setLocal enableDelayedExpansion
|
||||
set cp=.
|
||||
FOR %%i IN ("%~dp0libs\*.jar") DO set cp=!cp!;%%~fsi
|
||||
start "gateway-app-server" java -cp %cp% GatewayAppApplication
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash --login
|
||||
shopt -s expand_aliases
|
||||
|
||||
baseDir=$(cd "$(dirname "$0")"; pwd)
|
||||
cp=.
|
||||
for file in $baseDir/libs/*.jar
|
||||
do
|
||||
cp=$cp:$file
|
||||
done
|
||||
java -cp $cp me.zhengjie.AppRun >>stdout.out 2>&1 &
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import me.zhengjie.annotation.rest.AnonymousGetMapping;
|
||||
import me.zhengjie.utils.SpringContextHolder;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.ApplicationPidFileWriter;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 开启审计功能 -> @EnableJpaAuditing
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2018/11/15 9:20:19
|
||||
*/
|
||||
@EnableAsync
|
||||
@RestController
|
||||
@Api(hidden = true)
|
||||
@SpringBootApplication
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
|
||||
public class AppRun {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication springApplication = new SpringApplication(AppRun.class);
|
||||
// 监控应用的PID,启动时可指定PID路径:--spring.pid.file=/home/eladmin/app.pid
|
||||
// 或者在 application.yml 添加文件路径,方便 kill,kill `cat /home/eladmin/app.pid`
|
||||
springApplication.addListeners(new ApplicationPidFileWriter());
|
||||
springApplication.run(args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringContextHolder springContextHolder() {
|
||||
return new SpringContextHolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问首页提示
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
@AnonymousGetMapping("/")
|
||||
public String index() {
|
||||
return "Backend service started successfully";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* WebMvcConfigurer
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-30
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class ConfigurerAdapter implements WebMvcConfigurer {
|
||||
|
||||
/** 文件配置 */
|
||||
private final FileProperties properties;
|
||||
|
||||
public ConfigurerAdapter(FileProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true);
|
||||
config.addAllowedOriginPattern("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("*");
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
FileProperties.ElPath path = properties.getPath();
|
||||
String avatarUtl = "file:" + path.getAvatar().replace("\\","/");
|
||||
String pathUtl = "file:" + path.getPath().replace("\\","/");
|
||||
registry.addResourceHandler("/avatar/**").addResourceLocations(avatarUtl).setCachePeriod(0);
|
||||
registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0);
|
||||
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
// 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换
|
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||
List<MediaType> supportMediaTypeList = new ArrayList<>();
|
||||
supportMediaTypeList.add(MediaType.APPLICATION_JSON);
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
|
||||
converter.setFastJsonConfig(config);
|
||||
converter.setSupportedMediaTypes(supportMediaTypeList);
|
||||
converter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
converters.add(converter);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package me.zhengjie.config;
|
||||
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author bearBoy80
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class RelaxedQueryCharsConnectorCustomizer implements TomcatConnectorCustomizer {
|
||||
@Override
|
||||
public void customize(Connector connector) {
|
||||
connector.setProperty("relaxedQueryChars", "[]{}");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-24 15:44
|
||||
*/
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config.thread;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* 异步任务线程池装配类
|
||||
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
|
||||
* @date 2019年10月31日15:06:18
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class AsyncTaskExecutePool implements AsyncConfigurer {
|
||||
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
//核心线程池大小
|
||||
executor.setCorePoolSize(AsyncTaskProperties.corePoolSize);
|
||||
//最大线程数
|
||||
executor.setMaxPoolSize(AsyncTaskProperties.maxPoolSize);
|
||||
//队列容量
|
||||
executor.setQueueCapacity(AsyncTaskProperties.queueCapacity);
|
||||
//活跃时间
|
||||
executor.setKeepAliveSeconds(AsyncTaskProperties.keepAliveSeconds);
|
||||
//线程工厂
|
||||
executor.setThreadFactory(new TheadFactoryName("el-async"));
|
||||
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
|
||||
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||
return (throwable, method, objects) -> {
|
||||
log.error("===="+throwable.getMessage()+"====", throwable);
|
||||
log.error("exception method:"+method.getName());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config.thread;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 线程池配置属性类
|
||||
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
|
||||
* @date 2019年10月31日14:58:18
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
public class AsyncTaskProperties {
|
||||
|
||||
public static int corePoolSize;
|
||||
|
||||
public static int maxPoolSize;
|
||||
|
||||
public static int keepAliveSeconds;
|
||||
|
||||
public static int queueCapacity;
|
||||
|
||||
@Value("${task.pool.core-pool-size}")
|
||||
public void setCorePoolSize(int corePoolSize) {
|
||||
AsyncTaskProperties.corePoolSize = corePoolSize;
|
||||
}
|
||||
|
||||
@Value("${task.pool.max-pool-size}")
|
||||
public void setMaxPoolSize(int maxPoolSize) {
|
||||
AsyncTaskProperties.maxPoolSize = maxPoolSize;
|
||||
}
|
||||
|
||||
@Value("${task.pool.keep-alive-seconds}")
|
||||
public void setKeepAliveSeconds(int keepAliveSeconds) {
|
||||
AsyncTaskProperties.keepAliveSeconds = keepAliveSeconds;
|
||||
}
|
||||
|
||||
@Value("${task.pool.queue-capacity}")
|
||||
public void setQueueCapacity(int queueCapacity) {
|
||||
AsyncTaskProperties.queueCapacity = queueCapacity;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config.thread;
|
||||
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 自定义线程名称
|
||||
* @author Zheng Jie
|
||||
* @date 2019年10月31日17:49:55
|
||||
*/
|
||||
@Component
|
||||
public class TheadFactoryName implements ThreadFactory {
|
||||
|
||||
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
|
||||
private final ThreadGroup group;
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
private final String namePrefix;
|
||||
|
||||
private final static String DEF_NAME = "el-pool-";
|
||||
|
||||
public TheadFactoryName() {
|
||||
this(DEF_NAME);
|
||||
}
|
||||
|
||||
public TheadFactoryName(String name){
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
group = (s != null) ? s.getThreadGroup() :
|
||||
Thread.currentThread().getThreadGroup();
|
||||
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
|
||||
this.namePrefix = (StringUtils.isNotBlank(name) ? name : DEF_NAME) + "-" + POOL_NUMBER.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
//此时线程的名字 就是 namePrefix + -exec- + 这个线程池中第几个执行的线程
|
||||
Thread t = new Thread(group, r,
|
||||
namePrefix + "-exec-"+threadNumber.getAndIncrement(),
|
||||
0);
|
||||
if (t.isDaemon()) {
|
||||
t.setDaemon(false);
|
||||
}
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.config.thread;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 用于获取自定义线程池
|
||||
* @author Zheng Jie
|
||||
* @date 2019年10月31日18:16:47
|
||||
*/
|
||||
public class ThreadPoolExecutorUtil {
|
||||
|
||||
public static ExecutorService getPoll(){
|
||||
return getPoll(null);
|
||||
}
|
||||
|
||||
public static ExecutorService getPoll(String threadName){
|
||||
return new ThreadPoolExecutor(
|
||||
AsyncTaskProperties.corePoolSize,
|
||||
AsyncTaskProperties.maxPoolSize,
|
||||
AsyncTaskProperties.keepAliveSeconds,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<>(AsyncTaskProperties.queueCapacity),
|
||||
new TheadFactoryName(threadName),
|
||||
// 队列与线程池中线程都满了时使用调用者所在的线程来执行
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.modules.account.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import javax.persistence.*;
|
||||
import java.sql.Timestamp;
|
||||
import java.math.BigDecimal;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @website https://eladmin.vip
|
||||
* @description /
|
||||
* @author admin
|
||||
* @date 2023-10-30
|
||||
**/
|
||||
@Entity
|
||||
@Data
|
||||
@Table(name="bot_user_flow")
|
||||
public class BotUserFlow implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "`id`")
|
||||
@ApiModelProperty(value = "id")
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "`user_telegram_id`")
|
||||
@ApiModelProperty(value = "电报号")
|
||||
private String userTelegramId;
|
||||
|
||||
@Column(name = "`user_name`")
|
||||
@ApiModelProperty(value = "用户名称")
|
||||
private String userName;
|
||||
|
||||
@Column(name = "`biz_code`")
|
||||
@ApiModelProperty(value = "业务代码")
|
||||
private String bizCode;
|
||||
|
||||
@Column(name = "`amount`")
|
||||
@ApiModelProperty(value = "变动金额")
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "`old_balance`")
|
||||
@ApiModelProperty(value = "变动前金额")
|
||||
private BigDecimal oldBalance;
|
||||
|
||||
@Column(name = "`new_balance`")
|
||||
@ApiModelProperty(value = "变动后金额")
|
||||
private BigDecimal newBalance;
|
||||
|
||||
@Column(name = "`create_time`")
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private Timestamp createTime;
|
||||
|
||||
public void copy(BotUserFlow source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.modules.account.repository;
|
||||
|
||||
import me.zhengjie.modules.account.domain.BotUserFlow;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
/**
|
||||
* @website https://eladmin.vip
|
||||
* @author admin
|
||||
* @date 2023-10-30
|
||||
**/
|
||||
public interface BotUserFlowRepository extends JpaRepository<BotUserFlow, Integer>, JpaSpecificationExecutor<BotUserFlow> {
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package me.zhengjie.modules.account.rest;
|
||||
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.modules.account.domain.BotUserFlow;
|
||||
import me.zhengjie.modules.account.service.BotUserFlowService;
|
||||
import me.zhengjie.modules.account.service.dto.BotUserFlowQueryCriteria;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import io.swagger.annotations.*;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @website https://eladmin.vip
|
||||
* @author admin
|
||||
* @date 2023-10-30
|
||||
**/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "accountFlow管理")
|
||||
@RequestMapping("/api/botUserFlow")
|
||||
public class BotUserFlowController {
|
||||
|
||||
private final BotUserFlowService botUserFlowService;
|
||||
|
||||
@Log("导出数据")
|
||||
@ApiOperation("导出数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('botUserFlow:list')")
|
||||
public void exportBotUserFlow(HttpServletResponse response, BotUserFlowQueryCriteria criteria) throws IOException {
|
||||
botUserFlowService.download(botUserFlowService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@Log("查询accountFlow")
|
||||
@ApiOperation("查询accountFlow")
|
||||
@PreAuthorize("@el.check('botUserFlow:list')")
|
||||
public ResponseEntity<Object> queryBotUserFlow(BotUserFlowQueryCriteria criteria, Pageable pageable){
|
||||
return new ResponseEntity<>(botUserFlowService.queryAll(criteria,pageable),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Log("新增accountFlow")
|
||||
@ApiOperation("新增accountFlow")
|
||||
@PreAuthorize("@el.check('botUserFlow:add')")
|
||||
public ResponseEntity<Object> createBotUserFlow(@Validated @RequestBody BotUserFlow resources){
|
||||
return new ResponseEntity<>(botUserFlowService.create(resources),HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Log("修改accountFlow")
|
||||
@ApiOperation("修改accountFlow")
|
||||
@PreAuthorize("@el.check('botUserFlow:edit')")
|
||||
public ResponseEntity<Object> updateBotUserFlow(@Validated @RequestBody BotUserFlow resources){
|
||||
botUserFlowService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
@Log("删除accountFlow")
|
||||
@ApiOperation("删除accountFlow")
|
||||
@PreAuthorize("@el.check('botUserFlow:del')")
|
||||
public ResponseEntity<Object> deleteBotUserFlow(@RequestBody Integer[] ids) {
|
||||
botUserFlowService.deleteAll(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue