Compare commits
No commits in common. "main" and "master" have entirely different histories.
|
@ -0,0 +1,8 @@
|
||||||
|
### IDEA ###
|
||||||
|
.idea/*
|
||||||
|
*.iml
|
||||||
|
*/target/*
|
||||||
|
*/*.iml
|
||||||
|
/.gradle/
|
||||||
|
/application.pid
|
||||||
|
/.jpb/
|
|
@ -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-2023 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.
|
|
@ -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.7</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<properties>
|
||||||
|
<hutool.version>5.8.20</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,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.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,
|
||||||
|
// Aborn Jiang 2022/06/01, 对应SQL: SELECT * FROM table WHERE FIND_IN_SET('querytag', table.tags);
|
||||||
|
FIND_IN_SET
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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,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 AuthorityConfig {
|
||||||
|
|
||||||
|
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.ElConstant;
|
||||||
|
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(ElConstant.WIN)) {
|
||||||
|
return windows;
|
||||||
|
} else if(os.toLowerCase().startsWith(ElConstant.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
|
||||||
|
@SuppressWarnings({"all"})
|
||||||
|
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,151 @@
|
||||||
|
/*
|
||||||
|
* 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.7")
|
||||||
|
.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<>();
|
||||||
|
securityContexts.add(getContextByPath());
|
||||||
|
return securityContexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecurityContext getContextByPath() {
|
||||||
|
return SecurityContext.builder()
|
||||||
|
.securityReferences(defaultAuth())
|
||||||
|
// 表示 /auth/code、/auth/login 接口不需要使用securitySchemes即不需要带token
|
||||||
|
.operationSelector(o->o.requestMappingPattern().matches("^(?!/auth/code|/auth/login).*$"))
|
||||||
|
.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,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.exception.handler;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zheng Jie
|
||||||
|
* @date 2018-11-23
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
class ApiError {
|
||||||
|
|
||||||
|
private Integer status = 400;
|
||||||
|
private Long timestamp;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private ApiError() {
|
||||||
|
timestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
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,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.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常用静态常量
|
||||||
|
*
|
||||||
|
* @author Zheng Jie
|
||||||
|
* @date 2018-12-26
|
||||||
|
*/
|
||||||
|
public class ElConstant {
|
||||||
|
/**
|
||||||
|
* win 系统
|
||||||
|
*/
|
||||||
|
public static final String WIN = "win";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mac 系统
|
||||||
|
*/
|
||||||
|
public static final String MAC = "mac";
|
||||||
|
}
|
|
@ -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,395 @@
|
||||||
|
/*
|
||||||
|
* 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(verifyFilename(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证并过滤非法的文件名
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @return 文件名
|
||||||
|
*/
|
||||||
|
public static String verifyFilename(String fileName) {
|
||||||
|
// 过滤掉特殊字符
|
||||||
|
fileName = fileName.replaceAll("[\\\\/:*?\"<>|~\\s]", "");
|
||||||
|
|
||||||
|
// 去掉文件名开头和结尾的空格和点
|
||||||
|
fileName = fileName.trim().replaceAll("^[. ]+|[. ]+$", "");
|
||||||
|
|
||||||
|
// 不允许文件名超过255(在Mac和Linux中)或260(在Windows中)个字符
|
||||||
|
int maxFileNameLength = 255;
|
||||||
|
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||||
|
maxFileNameLength = 260;
|
||||||
|
}
|
||||||
|
if (fileName.length() > maxFileNameLength) {
|
||||||
|
fileName = fileName.substring(0, maxFileNameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤掉控制字符
|
||||||
|
fileName = fileName.replaceAll("[\\p{Cntrl}]", "");
|
||||||
|
|
||||||
|
// 过滤掉 ".." 路径
|
||||||
|
fileName = fileName.replaceAll("\\.{2,}", "");
|
||||||
|
|
||||||
|
// 去掉文件名开头的 ".."
|
||||||
|
fileName = fileName.replaceAll("^\\.+/", "");
|
||||||
|
|
||||||
|
// 保留文件名中最后一个 "." 字符,过滤掉其他 "."
|
||||||
|
fileName = fileName.replaceAll("^(.*)(\\.[^.]*)$", "$1").replaceAll("\\.", "") +
|
||||||
|
fileName.replaceAll("^(.*)(\\.[^.]*)$", "$2");
|
||||||
|
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String getMd5(File file) {
|
||||||
|
return getMd5(getByte(file));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package me.zhengjie.utils;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class PageResult<T> {
|
||||||
|
|
||||||
|
private final List<T> content;
|
||||||
|
|
||||||
|
private final long totalElements;
|
||||||
|
}
|
|
@ -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 <T> List<T> paging(int page, int size , List<T> list) {
|
||||||
|
int fromIndex = page * size;
|
||||||
|
int toIndex = page * size + size;
|
||||||
|
if(fromIndex > list.size()){
|
||||||
|
return Collections.emptyList();
|
||||||
|
} else if(toIndex >= list.size()) {
|
||||||
|
return list.subList(fromIndex,list.size());
|
||||||
|
} else {
|
||||||
|
return list.subList(fromIndex,toIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page 数据处理,预防redis反序列化报错
|
||||||
|
*/
|
||||||
|
public static <T> PageResult<T> toPage(Page<T> page) {
|
||||||
|
return new PageResult<>(page.getContent(), page.getTotalElements());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义分页
|
||||||
|
*/
|
||||||
|
public static <T> PageResult<T> toPage(List<T> list, long totalElements) {
|
||||||
|
return new PageResult<>(list, totalElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回空数据
|
||||||
|
*/
|
||||||
|
public static <T> PageResult<T> noData () {
|
||||||
|
return new PageResult<>(null, 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
Map<String, Join> joinKey = new HashMap<>();
|
||||||
|
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)) {
|
||||||
|
join = joinKey.get(joinName);
|
||||||
|
if(join == null){
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
joinKey.put(joinName, join);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
if(between.size() == 2){
|
||||||
|
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;
|
||||||
|
case FIND_IN_SET:
|
||||||
|
list.add(cb.greaterThan(cb.function("FIND_IN_SET", Integer.class,
|
||||||
|
cb.literal(val.toString()), root.get(attributeName)), 0));
|
||||||
|
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,725 @@
|
||||||
|
/*
|
||||||
|
* 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.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;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (redisTemplate.hasKey(key))
|
||||||
|
keySet.add(key);
|
||||||
|
}
|
||||||
|
long count = redisTemplate.delete(keySet);
|
||||||
|
log.debug("--------------------------------------------");
|
||||||
|
log.debug("成功删除缓存:" + keySet.toString());
|
||||||
|
log.debug("缓存删除数量:" + count + "个");
|
||||||
|
log.debug("--------------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量模糊删除key
|
||||||
|
* @param pattern
|
||||||
|
*/
|
||||||
|
public void scanDel(String pattern){
|
||||||
|
ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
|
||||||
|
try (Cursor<byte[]> cursor = redisTemplate.executeWithStickyConnection(
|
||||||
|
(RedisCallback<Cursor<byte[]>>) connection -> (Cursor<byte[]>) new ConvertingCursor<>(
|
||||||
|
connection.scan(options), redisTemplate.getKeySerializer()::deserialize))) {
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
redisTemplate.delete(cursor.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================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 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
|
||||||
|
* @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,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.utils;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
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();
|
||||||
|
// 将 Java 对象转换为 JSONObject 对象
|
||||||
|
JSONObject jsonObject = (JSONObject) JSON.toJSON(userDetails);
|
||||||
|
return jsonObject.getJSONObject("user").getLong("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户的数据权限
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
public static List<Long> getCurrentUserDataScope(){
|
||||||
|
UserDetails userDetails = getCurrentUser();
|
||||||
|
// 将 Java 对象转换为 JSONObject 对象
|
||||||
|
JSONObject jsonObject = (JSONObject) JSON.toJSON(userDetails);
|
||||||
|
JSONArray jsonArray = jsonObject.getJSONArray("dataScopes");
|
||||||
|
return JSON.parseArray(jsonArray.toJSONString(), 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,232 @@
|
||||||
|
/*
|
||||||
|
* 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.useragent.UserAgent;
|
||||||
|
import cn.hutool.http.useragent.UserAgentUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
|
||||||
|
import net.dreamlu.mica.ip2region.core.IpInfo;
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驼峰命名法工具
|
||||||
|
*
|
||||||
|
* @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) {
|
||||||
|
IpInfo ipInfo = IP_SEARCHER.memorySearch(ip);
|
||||||
|
if(ipInfo != null){
|
||||||
|
return ipInfo.getAddress();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getBrowser(HttpServletRequest request) {
|
||||||
|
UserAgent ua = UserAgentUtil.parse(request.getHeader("User-Agent"));
|
||||||
|
String browser = ua.getBrowser().toString() + " " + ua.getVersion();
|
||||||
|
return browser.replace(".0.0.0","");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得当天是周几
|
||||||
|
*/
|
||||||
|
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,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.7</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.7</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<GenConfig> 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,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.domain.ColumnInfo;
|
||||||
|
import me.zhengjie.domain.vo.TableInfo;
|
||||||
|
import me.zhengjie.exception.BadRequestException;
|
||||||
|
import me.zhengjie.service.GenConfigService;
|
||||||
|
import me.zhengjie.service.GeneratorService;
|
||||||
|
import me.zhengjie.utils.PageResult;
|
||||||
|
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<PageResult<TableInfo>> 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<PageResult<ColumnInfo>> 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,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.service;
|
||||||
|
|
||||||
|
import me.zhengjie.domain.GenConfig;
|
||||||
|
import me.zhengjie.domain.ColumnInfo;
|
||||||
|
import me.zhengjie.domain.vo.TableInfo;
|
||||||
|
import me.zhengjie.utils.PageResult;
|
||||||
|
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 /
|
||||||
|
*/
|
||||||
|
PageResult<TableInfo> 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,204 @@
|
||||||
|
/*
|
||||||
|
* 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.*;
|
||||||
|
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.math.BigInteger;
|
||||||
|
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 PageResult<TableInfo> 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 + "%") : "%%");
|
||||||
|
BigInteger totalElements = (BigInteger) queryCount.getSingleResult();
|
||||||
|
return PageUtil.toPage(tableInfos, totalElements.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@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("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("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("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("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("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("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,27 @@
|
||||||
|
# Database type to Java type
|
||||||
|
tinyint=Integer
|
||||||
|
smallint=Integer
|
||||||
|
mediumint=Integer
|
||||||
|
int=Integer
|
||||||
|
integer=Integer
|
||||||
|
|
||||||
|
bigint=Long
|
||||||
|
|
||||||
|
float=Float
|
||||||
|
|
||||||
|
double=Double
|
||||||
|
|
||||||
|
decimal=BigDecimal
|
||||||
|
|
||||||
|
bit=Boolean
|
||||||
|
|
||||||
|
char=String
|
||||||
|
varchar=String
|
||||||
|
tinytext=String
|
||||||
|
text=String
|
||||||
|
mediumtext=String
|
||||||
|
longtext=String
|
||||||
|
|
||||||
|
date=Timestamp
|
||||||
|
datetime=Timestamp
|
||||||
|
timestamp=Timestamp
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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 ${package}.rest;
|
||||||
|
|
||||||
|
import me.zhengjie.annotation.Log;
|
||||||
|
import ${package}.domain.${className};
|
||||||
|
import ${package}.service.${className}Service;
|
||||||
|
import ${package}.service.dto.${className}QueryCriteria;
|
||||||
|
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;
|
||||||
|
import me.zhengjie.utils.PageResult;
|
||||||
|
import ${package}.service.dto.${className}Dto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Api(tags = "${apiAlias}管理")
|
||||||
|
@RequestMapping("/api/${changeClassName}")
|
||||||
|
public class ${className}Controller {
|
||||||
|
|
||||||
|
private final ${className}Service ${changeClassName}Service;
|
||||||
|
|
||||||
|
@Log("导出数据")
|
||||||
|
@ApiOperation("导出数据")
|
||||||
|
@GetMapping(value = "/download")
|
||||||
|
@PreAuthorize("@el.check('${changeClassName}:list')")
|
||||||
|
public void export${className}(HttpServletResponse response, ${className}QueryCriteria criteria) throws IOException {
|
||||||
|
${changeClassName}Service.download(${changeClassName}Service.queryAll(criteria), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
@Log("查询${apiAlias}")
|
||||||
|
@ApiOperation("查询${apiAlias}")
|
||||||
|
@PreAuthorize("@el.check('${changeClassName}:list')")
|
||||||
|
public ResponseEntity<PageResult<${className}Dto>> query${className}(${className}QueryCriteria criteria, Pageable pageable){
|
||||||
|
return new ResponseEntity<>(${changeClassName}Service.queryAll(criteria,pageable),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
@Log("新增${apiAlias}")
|
||||||
|
@ApiOperation("新增${apiAlias}")
|
||||||
|
@PreAuthorize("@el.check('${changeClassName}:add')")
|
||||||
|
public ResponseEntity<Object> create${className}(@Validated @RequestBody ${className} resources){
|
||||||
|
${changeClassName}Service.create(resources);
|
||||||
|
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping
|
||||||
|
@Log("修改${apiAlias}")
|
||||||
|
@ApiOperation("修改${apiAlias}")
|
||||||
|
@PreAuthorize("@el.check('${changeClassName}:edit')")
|
||||||
|
public ResponseEntity<Object> update${className}(@Validated @RequestBody ${className} resources){
|
||||||
|
${changeClassName}Service.update(resources);
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
@Log("删除${apiAlias}")
|
||||||
|
@ApiOperation("删除${apiAlias}")
|
||||||
|
@PreAuthorize("@el.check('${changeClassName}:del')")
|
||||||
|
public ResponseEntity<Object> delete${className}(@RequestBody ${pkColumnType}[] ids) {
|
||||||
|
${changeClassName}Service.deleteAll(ids);
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 ${package}.service.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
<#if hasTimestamp>
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
</#if>
|
||||||
|
<#if hasBigDecimal>
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
</#if>
|
||||||
|
import java.io.Serializable;
|
||||||
|
<#if !auto && pkColumnType = 'Long'>
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.alibaba.fastjson.serializer.ToStringSerializer;
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @description /
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class ${className}Dto implements Serializable {
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
|
||||||
|
<#if column.remark != ''>
|
||||||
|
/** ${column.remark} */
|
||||||
|
</#if>
|
||||||
|
<#if column.columnKey = 'PRI'>
|
||||||
|
<#if !auto && pkColumnType = 'Long'>
|
||||||
|
/** 防止精度丢失 */
|
||||||
|
@JSONField(serializeUsing = ToStringSerializer.class)
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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 ${package}.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.*;
|
||||||
|
<#if isNotNullColumns??>
|
||||||
|
import javax.validation.constraints.*;
|
||||||
|
</#if>
|
||||||
|
<#if hasDateAnnotation>
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import org.hibernate.annotations.*;
|
||||||
|
</#if>
|
||||||
|
<#if hasTimestamp>
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
</#if>
|
||||||
|
<#if hasBigDecimal>
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
</#if>
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @description /
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
@Entity
|
||||||
|
@Data
|
||||||
|
@Table(name="${tableName}")
|
||||||
|
public class ${className} implements Serializable {
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
|
||||||
|
<#if column.columnKey = 'PRI'>
|
||||||
|
@Id
|
||||||
|
<#if auto>
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
@Column(name = "`${column.columnName}`"<#if column.columnKey = 'UNI'>,unique = true</#if><#if column.istNotNull && column.columnKey != 'PRI'>,nullable = false</#if>)
|
||||||
|
<#if column.istNotNull && column.columnKey != 'PRI'>
|
||||||
|
<#if column.columnType = 'String'>
|
||||||
|
@NotBlank
|
||||||
|
<#else>
|
||||||
|
@NotNull
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
<#if (column.dateAnnotation)?? && column.dateAnnotation != ''>
|
||||||
|
<#if column.dateAnnotation = 'CreationTimestamp'>
|
||||||
|
@CreationTimestamp
|
||||||
|
<#else>
|
||||||
|
@UpdateTimestamp
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
<#if column.remark != ''>
|
||||||
|
@ApiModelProperty(value = "${column.remark}")
|
||||||
|
<#else>
|
||||||
|
@ApiModelProperty(value = "${column.changeColumnName}")
|
||||||
|
</#if>
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
public void copy(${className} source){
|
||||||
|
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 ${package}.service.mapstruct;
|
||||||
|
|
||||||
|
import me.zhengjie.base.BaseMapper;
|
||||||
|
import ${package}.domain.${className};
|
||||||
|
import ${package}.service.dto.${className}Dto;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
|
public interface ${className}Mapper extends BaseMapper<${className}Dto, ${className}> {
|
||||||
|
|
||||||
|
}
|
|
@ -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 ${package}.service.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
<#if queryHasTimestamp>
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
</#if>
|
||||||
|
<#if queryHasBigDecimal>
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
</#if>
|
||||||
|
<#if betweens??>
|
||||||
|
import java.util.List;
|
||||||
|
</#if>
|
||||||
|
<#if queryColumns??>
|
||||||
|
import me.zhengjie.annotation.Query;
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class ${className}QueryCriteria{
|
||||||
|
<#if queryColumns??>
|
||||||
|
<#list queryColumns as column>
|
||||||
|
|
||||||
|
<#if column.queryType = '='>
|
||||||
|
/** 精确 */
|
||||||
|
@Query
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#if>
|
||||||
|
<#if column.queryType = 'Like'>
|
||||||
|
/** 模糊 */
|
||||||
|
@Query(type = Query.Type.INNER_LIKE)
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#if>
|
||||||
|
<#if column.queryType = '!='>
|
||||||
|
/** 不等于 */
|
||||||
|
@Query(type = Query.Type.NOT_EQUAL)
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#if>
|
||||||
|
<#if column.queryType = 'NotNull'>
|
||||||
|
/** 不为空 */
|
||||||
|
@Query(type = Query.Type.NOT_NULL)
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#if>
|
||||||
|
<#if column.queryType = '>='>
|
||||||
|
/** 大于等于 */
|
||||||
|
@Query(type = Query.Type.GREATER_THAN)
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#if>
|
||||||
|
<#if column.queryType = '<='>
|
||||||
|
/** 小于等于 */
|
||||||
|
@Query(type = Query.Type.LESS_THAN)
|
||||||
|
private ${column.columnType} ${column.changeColumnName};
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#if betweens??>
|
||||||
|
<#list betweens as column>
|
||||||
|
/** BETWEEN */
|
||||||
|
@Query(type = Query.Type.BETWEEN)
|
||||||
|
private List<${column.columnType}> ${column.changeColumnName};
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
}
|
|
@ -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 ${package}.repository;
|
||||||
|
|
||||||
|
import ${package}.domain.${className};
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
public interface ${className}Repository extends JpaRepository<${className}, ${pkColumnType}>, JpaSpecificationExecutor<${className}> {
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.columnKey = 'UNI'>
|
||||||
|
/**
|
||||||
|
* 根据 ${column.capitalColumnName} 查询
|
||||||
|
* @param ${column.columnName} /
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
${className} findBy${column.capitalColumnName}(${column.columnType} ${column.columnName});
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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 ${package}.service;
|
||||||
|
|
||||||
|
import ${package}.domain.${className};
|
||||||
|
import ${package}.service.dto.${className}Dto;
|
||||||
|
import ${package}.service.dto.${className}QueryCriteria;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.List;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import me.zhengjie.utils.PageResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @description 服务接口
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
public interface ${className}Service {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询数据分页
|
||||||
|
* @param criteria 条件
|
||||||
|
* @param pageable 分页参数
|
||||||
|
* @return Map<String,Object>
|
||||||
|
*/
|
||||||
|
PageResult<${className}Dto> queryAll(${className}QueryCriteria criteria, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有数据不分页
|
||||||
|
* @param criteria 条件参数
|
||||||
|
* @return List<${className}Dto>
|
||||||
|
*/
|
||||||
|
List<${className}Dto> queryAll(${className}QueryCriteria criteria);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询
|
||||||
|
* @param ${pkChangeColName} ID
|
||||||
|
* @return ${className}Dto
|
||||||
|
*/
|
||||||
|
${className}Dto findById(${pkColumnType} ${pkChangeColName});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建
|
||||||
|
* @param resources /
|
||||||
|
*/
|
||||||
|
void create(${className} resources);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑
|
||||||
|
* @param resources /
|
||||||
|
*/
|
||||||
|
void update(${className} resources);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多选删除
|
||||||
|
* @param ids /
|
||||||
|
*/
|
||||||
|
void deleteAll(${pkColumnType}[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出数据
|
||||||
|
* @param all 待导出的数据
|
||||||
|
* @param response /
|
||||||
|
* @throws IOException /
|
||||||
|
*/
|
||||||
|
void download(List<${className}Dto> all, HttpServletResponse response) throws IOException;
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* 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 ${package}.service.impl;
|
||||||
|
|
||||||
|
import ${package}.domain.${className};
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.columnKey = 'UNI'>
|
||||||
|
<#if column_index = 1>
|
||||||
|
import me.zhengjie.exception.EntityExistException;
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
import me.zhengjie.utils.ValidationUtil;
|
||||||
|
import me.zhengjie.utils.FileUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import ${package}.repository.${className}Repository;
|
||||||
|
import ${package}.service.${className}Service;
|
||||||
|
import ${package}.service.dto.${className}Dto;
|
||||||
|
import ${package}.service.dto.${className}QueryCriteria;
|
||||||
|
import ${package}.service.mapstruct.${className}Mapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
<#if !auto && pkColumnType = 'Long'>
|
||||||
|
import cn.hutool.core.lang.Snowflake;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
</#if>
|
||||||
|
<#if !auto && pkColumnType = 'String'>
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
</#if>
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import me.zhengjie.utils.PageUtil;
|
||||||
|
import me.zhengjie.utils.QueryHelp;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import me.zhengjie.utils.PageResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @website https://eladmin.vip
|
||||||
|
* @description 服务实现
|
||||||
|
* @author ${author}
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ${className}ServiceImpl implements ${className}Service {
|
||||||
|
|
||||||
|
private final ${className}Repository ${changeClassName}Repository;
|
||||||
|
private final ${className}Mapper ${changeClassName}Mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<${className}Dto> queryAll(${className}QueryCriteria criteria, Pageable pageable){
|
||||||
|
Page<${className}> page = ${changeClassName}Repository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
|
||||||
|
return PageUtil.toPage(page.map(${changeClassName}Mapper::toDto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<${className}Dto> queryAll(${className}QueryCriteria criteria){
|
||||||
|
return ${changeClassName}Mapper.toDto(${changeClassName}Repository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public ${className}Dto findById(${pkColumnType} ${pkChangeColName}) {
|
||||||
|
${className} ${changeClassName} = ${changeClassName}Repository.findById(${pkChangeColName}).orElseGet(${className}::new);
|
||||||
|
ValidationUtil.isNull(${changeClassName}.get${pkCapitalColName}(),"${className}","${pkChangeColName}",${pkChangeColName});
|
||||||
|
return ${changeClassName}Mapper.toDto(${changeClassName});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void create(${className} resources) {
|
||||||
|
<#if !auto && pkColumnType = 'Long'>
|
||||||
|
Snowflake snowflake = IdUtil.createSnowflake(1, 1);
|
||||||
|
resources.set${pkCapitalColName}(snowflake.nextId());
|
||||||
|
</#if>
|
||||||
|
<#if !auto && pkColumnType = 'String'>
|
||||||
|
resources.set${pkCapitalColName}(IdUtil.simpleUUID());
|
||||||
|
</#if>
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.columnKey = 'UNI'>
|
||||||
|
if(${changeClassName}Repository.findBy${column.capitalColumnName}(resources.get${column.capitalColumnName}()) != null){
|
||||||
|
throw new EntityExistException(${className}.class,"${column.columnName}",resources.get${column.capitalColumnName}());
|
||||||
|
}
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
${changeClassName}Repository.save(resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void update(${className} resources) {
|
||||||
|
${className} ${changeClassName} = ${changeClassName}Repository.findById(resources.get${pkCapitalColName}()).orElseGet(${className}::new);
|
||||||
|
ValidationUtil.isNull( ${changeClassName}.get${pkCapitalColName}(),"${className}","id",resources.get${pkCapitalColName}());
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.columnKey = 'UNI'>
|
||||||
|
<#if column_index = 1>
|
||||||
|
${className} ${changeClassName}1 = null;
|
||||||
|
</#if>
|
||||||
|
${changeClassName}1 = ${changeClassName}Repository.findBy${column.capitalColumnName}(resources.get${column.capitalColumnName}());
|
||||||
|
if(${changeClassName}1 != null && !${changeClassName}1.get${pkCapitalColName}().equals(${changeClassName}.get${pkCapitalColName}())){
|
||||||
|
throw new EntityExistException(${className}.class,"${column.columnName}",resources.get${column.capitalColumnName}());
|
||||||
|
}
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
${changeClassName}.copy(resources);
|
||||||
|
${changeClassName}Repository.save(${changeClassName});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAll(${pkColumnType}[] ids) {
|
||||||
|
for (${pkColumnType} ${pkChangeColName} : ids) {
|
||||||
|
${changeClassName}Repository.deleteById(${pkChangeColName});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void download(List<${className}Dto> all, HttpServletResponse response) throws IOException {
|
||||||
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
|
for (${className}Dto ${changeClassName} : all) {
|
||||||
|
Map<String,Object> map = new LinkedHashMap<>();
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.columnKey != 'PRI'>
|
||||||
|
<#if column.remark != ''>
|
||||||
|
map.put("${column.remark}", ${changeClassName}.get${column.capitalColumnName}());
|
||||||
|
<#else>
|
||||||
|
map.put(" ${column.changeColumnName}", ${changeClassName}.get${column.capitalColumnName}());
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
list.add(map);
|
||||||
|
}
|
||||||
|
FileUtil.downloadExcel(list, response);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function add(data) {
|
||||||
|
return request({
|
||||||
|
url: 'api/${changeClassName}',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function del(ids) {
|
||||||
|
return request({
|
||||||
|
url: 'api/${changeClassName}/',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function edit(data) {
|
||||||
|
return request({
|
||||||
|
url: 'api/${changeClassName}',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { add, edit, del }
|
|
@ -0,0 +1,169 @@
|
||||||
|
<#--noinspection ALL-->
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<!--工具栏-->
|
||||||
|
<div class="head-container">
|
||||||
|
<#if hasQuery>
|
||||||
|
<div v-if="crud.props.searchToggle">
|
||||||
|
<!-- 搜索 -->
|
||||||
|
<#if queryColumns??>
|
||||||
|
<#list queryColumns as column>
|
||||||
|
<#if column.queryType != 'BetWeen'>
|
||||||
|
<label class="el-form-item-label"><#if column.remark != ''>${column.remark}<#else>${column.changeColumnName}</#if></label>
|
||||||
|
<el-input v-model="query.${column.changeColumnName}" clearable placeholder="<#if column.remark != ''>${column.remark}<#else>${column.changeColumnName}</#if>" style="width: 185px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#if betweens??>
|
||||||
|
<#list betweens as column>
|
||||||
|
<#if column.queryType = 'BetWeen'>
|
||||||
|
<date-range-picker
|
||||||
|
v-model="query.${column.changeColumnName}"
|
||||||
|
start-placeholder="${column.changeColumnName}Start"
|
||||||
|
end-placeholder="${column.changeColumnName}Start"
|
||||||
|
class="date-item"
|
||||||
|
/>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<rrOperation :crud="crud" />
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
<!--如果想在工具栏加入更多按钮,可以使用插槽方式, slot = 'left' or 'right'-->
|
||||||
|
<crudOperation :permission="permission" />
|
||||||
|
<!--表单组件-->
|
||||||
|
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="800px">
|
||||||
|
<el-form ref="form" :model="form" <#if isNotNullColumns??>:rules="rules"</#if> size="small" label-width="150px">
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.formShow>
|
||||||
|
<el-form-item label="<#if column.remark != ''>${column.remark}<#else>${column.changeColumnName}</#if>"<#if column.istNotNull> prop="${column.changeColumnName}"</#if>>
|
||||||
|
<#if column.formType = 'Input'>
|
||||||
|
<el-input v-model="form.${column.changeColumnName}" />
|
||||||
|
<#elseif column.formType = 'Textarea'>
|
||||||
|
<el-input v-model="form.${column.changeColumnName}" :rows="3" type="textarea" />
|
||||||
|
<#elseif column.formType = 'Radio'>
|
||||||
|
<#if (column.dictName)?? && (column.dictName)!="">
|
||||||
|
<el-radio v-model="form.${column.changeColumnName}" v-for="item in dict.${column.dictName}" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
|
||||||
|
<#else>
|
||||||
|
未设置字典,请手动设置 Radio
|
||||||
|
</#if>
|
||||||
|
<#elseif column.formType = 'Select'>
|
||||||
|
<#if (column.dictName)?? && (column.dictName)!="">
|
||||||
|
<el-select v-model="form.${column.changeColumnName}" filterable placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="item in dict.${column.dictName}"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
<#else>
|
||||||
|
未设置字典,请手动设置 Select
|
||||||
|
</#if>
|
||||||
|
<#else>
|
||||||
|
<el-date-picker v-model="form.${column.changeColumnName}" type="datetime" />
|
||||||
|
</#if>
|
||||||
|
</el-form-item>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="text" @click="crud.cancelCU">取消</el-button>
|
||||||
|
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<!--表格渲染-->
|
||||||
|
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<#if columns??>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.columnShow>
|
||||||
|
<#if (column.dictName)?? && (column.dictName)!="">
|
||||||
|
<el-table-column prop="${column.changeColumnName}" label="<#if column.remark != ''>${column.remark}<#else>${column.changeColumnName}</#if>">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ dict.label.${column.dictName}[scope.row.${column.changeColumnName}] }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<#else>
|
||||||
|
<el-table-column prop="${column.changeColumnName}" label="<#if column.remark != ''>${column.remark}<#else>${column.changeColumnName}</#if>" />
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<el-table-column v-if="checkPer(['admin','${changeClassName}:edit','${changeClassName}:del'])" label="操作" width="150px" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<udOperation
|
||||||
|
:data="scope.row"
|
||||||
|
:permission="permission"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--分页组件-->
|
||||||
|
<pagination />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import crud${className} from '@/api/${changeClassName}'
|
||||||
|
import CRUD, { presenter, header, form, crud } from '@crud/crud'
|
||||||
|
import rrOperation from '@crud/RR.operation'
|
||||||
|
import crudOperation from '@crud/CRUD.operation'
|
||||||
|
import udOperation from '@crud/UD.operation'
|
||||||
|
import pagination from '@crud/Pagination'
|
||||||
|
|
||||||
|
const defaultForm = { <#if columns??><#list columns as column>${column.changeColumnName}: null<#if column_has_next>, </#if></#list></#if> }
|
||||||
|
export default {
|
||||||
|
name: '${className}',
|
||||||
|
components: { pagination, crudOperation, rrOperation, udOperation },
|
||||||
|
mixins: [presenter(), header(), form(defaultForm), crud()],
|
||||||
|
<#if hasDict>
|
||||||
|
dicts: [<#if hasDict??><#list dicts as dict>'${dict}'<#if dict_has_next>, </#if></#list></#if>],
|
||||||
|
</#if>
|
||||||
|
cruds() {
|
||||||
|
return CRUD({ title: '${apiAlias}', url: 'api/${changeClassName}', idField: '${pkChangeColName}', sort: '${pkChangeColName},desc', crudMethod: { ...crud${className} }})
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
permission: {
|
||||||
|
add: ['admin', '${changeClassName}:add'],
|
||||||
|
edit: ['admin', '${changeClassName}:edit'],
|
||||||
|
del: ['admin', '${changeClassName}:del']
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
<#if isNotNullColumns??>
|
||||||
|
<#list isNotNullColumns as column>
|
||||||
|
<#if column.istNotNull>
|
||||||
|
${column.changeColumnName}: [
|
||||||
|
{ required: true, message: '<#if column.remark != ''>${column.remark}</#if>不能为空', trigger: 'blur' }
|
||||||
|
]<#if column_has_next>,</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
}<#if hasQuery>,
|
||||||
|
queryTypeOptions: [
|
||||||
|
<#if queryColumns??>
|
||||||
|
<#list queryColumns as column>
|
||||||
|
<#if column.queryType != 'BetWeen'>
|
||||||
|
{ key: '${column.changeColumnName}', display_name: '<#if column.remark != ''>${column.remark}<#else>${column.changeColumnName}</#if>' }<#if column_has_next>,</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
]
|
||||||
|
</#if>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 钩子:在获取表格数据之前执行,false 则代表不获取数据
|
||||||
|
[CRUD.HOOK.beforeRefresh]() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -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.7</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.7</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.SysLog;
|
||||||
|
import me.zhengjie.service.SysLogService;
|
||||||
|
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 SysLogService sysLogService;
|
||||||
|
|
||||||
|
ThreadLocal<Long> currentTime = new ThreadLocal<>();
|
||||||
|
|
||||||
|
public LogAspect(SysLogService sysLogService) {
|
||||||
|
this.sysLogService = sysLogService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置切入点
|
||||||
|
*/
|
||||||
|
@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();
|
||||||
|
SysLog sysLog = new SysLog("INFO",System.currentTimeMillis() - currentTime.get());
|
||||||
|
currentTime.remove();
|
||||||
|
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||||
|
sysLogService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, sysLog);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置异常通知
|
||||||
|
*
|
||||||
|
* @param joinPoint join point for advice
|
||||||
|
* @param e exception
|
||||||
|
*/
|
||||||
|
@AfterThrowing(pointcut = "logPointcut()", throwing = "e")
|
||||||
|
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
|
||||||
|
SysLog sysLog = new SysLog("ERROR",System.currentTimeMillis() - currentTime.get());
|
||||||
|
currentTime.remove();
|
||||||
|
sysLog.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
|
||||||
|
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||||
|
sysLogService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, sysLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 SysLog 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 SysLog(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.SysLog;
|
||||||
|
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<SysLog,Long>, JpaSpecificationExecutor<SysLog> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据日志类型删除信息
|
||||||
|
* @param logType 日志类型
|
||||||
|
*/
|
||||||
|
@Modifying
|
||||||
|
@Query(value = "delete from sys_log where log_type = ?1", nativeQuery = true)
|
||||||
|
void deleteByLogType(String logType);
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* 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.SysLogService;
|
||||||
|
import me.zhengjie.service.dto.SysLogQueryCriteria;
|
||||||
|
import me.zhengjie.service.dto.SysLogSmallDto;
|
||||||
|
import me.zhengjie.utils.PageResult;
|
||||||
|
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 SysLogController {
|
||||||
|
|
||||||
|
private final SysLogService sysLogService;
|
||||||
|
|
||||||
|
@Log("导出数据")
|
||||||
|
@ApiOperation("导出数据")
|
||||||
|
@GetMapping(value = "/download")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public void exportLog(HttpServletResponse response, SysLogQueryCriteria criteria) throws IOException {
|
||||||
|
criteria.setLogType("INFO");
|
||||||
|
sysLogService.download(sysLogService.queryAll(criteria), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log("导出错误数据")
|
||||||
|
@ApiOperation("导出错误数据")
|
||||||
|
@GetMapping(value = "/error/download")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public void exportErrorLog(HttpServletResponse response, SysLogQueryCriteria criteria) throws IOException {
|
||||||
|
criteria.setLogType("ERROR");
|
||||||
|
sysLogService.download(sysLogService.queryAll(criteria), response);
|
||||||
|
}
|
||||||
|
@GetMapping
|
||||||
|
@ApiOperation("日志查询")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<Object> queryLog(SysLogQueryCriteria criteria, Pageable pageable){
|
||||||
|
criteria.setLogType("INFO");
|
||||||
|
return new ResponseEntity<>(sysLogService.queryAll(criteria,pageable), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/user")
|
||||||
|
@ApiOperation("用户日志查询")
|
||||||
|
public ResponseEntity<PageResult<SysLogSmallDto>> queryUserLog(SysLogQueryCriteria criteria, Pageable pageable){
|
||||||
|
criteria.setLogType("INFO");
|
||||||
|
criteria.setUsername(SecurityUtils.getCurrentUsername());
|
||||||
|
return new ResponseEntity<>(sysLogService.queryAllByUser(criteria,pageable), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/error")
|
||||||
|
@ApiOperation("错误日志查询")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<Object> queryErrorLog(SysLogQueryCriteria criteria, Pageable pageable){
|
||||||
|
criteria.setLogType("ERROR");
|
||||||
|
return new ResponseEntity<>(sysLogService.queryAll(criteria,pageable), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/error/{id}")
|
||||||
|
@ApiOperation("日志异常详情查询")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<Object> queryErrorLogDetail(@PathVariable Long id){
|
||||||
|
return new ResponseEntity<>(sysLogService.findByErrDetail(id), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
@DeleteMapping(value = "/del/error")
|
||||||
|
@Log("删除所有ERROR日志")
|
||||||
|
@ApiOperation("删除所有ERROR日志")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<Object> delAllErrorLog(){
|
||||||
|
sysLogService.delAllByError();
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/del/info")
|
||||||
|
@Log("删除所有INFO日志")
|
||||||
|
@ApiOperation("删除所有INFO日志")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<Object> delAllInfoLog(){
|
||||||
|
sysLogService.delAllByInfo();
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* 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.SysLog;
|
||||||
|
import me.zhengjie.service.dto.SysLogQueryCriteria;
|
||||||
|
import me.zhengjie.service.dto.SysLogSmallDto;
|
||||||
|
import me.zhengjie.utils.PageResult;
|
||||||
|
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 SysLogService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询
|
||||||
|
* @param criteria 查询条件
|
||||||
|
* @param pageable 分页参数
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
Object queryAll(SysLogQueryCriteria criteria, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询全部数据
|
||||||
|
* @param criteria 查询条件
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
List<SysLog> queryAll(SysLogQueryCriteria criteria);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户日志
|
||||||
|
* @param criteria 查询条件
|
||||||
|
* @param pageable 分页参数
|
||||||
|
* @return -
|
||||||
|
*/
|
||||||
|
PageResult<SysLogSmallDto> queryAllByUser(SysLogQueryCriteria criteria, Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存日志数据
|
||||||
|
* @param username 用户
|
||||||
|
* @param browser 浏览器
|
||||||
|
* @param ip 请求IP
|
||||||
|
* @param joinPoint /
|
||||||
|
* @param sysLog 日志实体
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, SysLog sysLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询异常详情
|
||||||
|
* @param id 日志ID
|
||||||
|
* @return Object
|
||||||
|
*/
|
||||||
|
Object findByErrDetail(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出日志
|
||||||
|
* @param sysLogs 待导出的数据
|
||||||
|
* @param response /
|
||||||
|
* @throws IOException /
|
||||||
|
*/
|
||||||
|
void download(List<SysLog> sysLogs, 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 SysLogErrorDto 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 SysLogQueryCriteria {
|
||||||
|
|
||||||
|
@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 SysLogSmallDto implements Serializable {
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String requestIp;
|
||||||
|
|
||||||
|
private Long time;
|
||||||
|
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
private String browser;
|
||||||
|
|
||||||
|
private Timestamp createTime;
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* 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 com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import me.zhengjie.domain.SysLog;
|
||||||
|
import me.zhengjie.repository.LogRepository;
|
||||||
|
import me.zhengjie.service.SysLogService;
|
||||||
|
import me.zhengjie.service.dto.SysLogQueryCriteria;
|
||||||
|
import me.zhengjie.service.dto.SysLogSmallDto;
|
||||||
|
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 org.springframework.web.multipart.MultipartFile;
|
||||||
|
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 SysLogServiceImpl implements SysLogService {
|
||||||
|
private final LogRepository logRepository;
|
||||||
|
private final LogErrorMapper logErrorMapper;
|
||||||
|
private final LogSmallMapper logSmallMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object queryAll(SysLogQueryCriteria criteria, Pageable pageable) {
|
||||||
|
Page<SysLog> 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 PageUtil.toPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysLog> queryAll(SysLogQueryCriteria criteria) {
|
||||||
|
return logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<SysLogSmallDto> queryAllByUser(SysLogQueryCriteria criteria, Pageable pageable) {
|
||||||
|
Page<SysLog> 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, SysLog sysLog) {
|
||||||
|
if (sysLog == 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() + "()";
|
||||||
|
|
||||||
|
// 描述
|
||||||
|
sysLog.setDescription(aopLog.value());
|
||||||
|
|
||||||
|
sysLog.setRequestIp(ip);
|
||||||
|
sysLog.setAddress(StringUtils.getCityInfo(sysLog.getRequestIp()));
|
||||||
|
sysLog.setMethod(methodName);
|
||||||
|
sysLog.setUsername(username);
|
||||||
|
sysLog.setParams(getParameter(method, joinPoint.getArgs()));
|
||||||
|
// 记录登录用户,隐藏密码信息
|
||||||
|
if(signature.getName().equals("login") && StringUtils.isNotEmpty(sysLog.getParams())){
|
||||||
|
JSONObject obj = JSON.parseObject(sysLog.getParams());
|
||||||
|
sysLog.setUsername(obj.getString("username"));
|
||||||
|
sysLog.setParams(JSON.toJSONString(Dict.create().set("username", sysLog.getUsername())));
|
||||||
|
}
|
||||||
|
sysLog.setBrowser(browser);
|
||||||
|
logRepository.save(sysLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据方法和传入的参数获取请求参数
|
||||||
|
*/
|
||||||
|
private String getParameter(Method method, Object[] args) {
|
||||||
|
List<Object> argList = new ArrayList<>();
|
||||||
|
Parameter[] parameters = method.getParameters();
|
||||||
|
for (int i = 0; i < parameters.length; i++) {
|
||||||
|
// 过滤掉不能序列化的类型: MultiPartFile
|
||||||
|
if (args[i] instanceof MultipartFile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//将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 ? JSON.toJSONString(argList.get(0)) : JSON.toJSONString(argList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object findByErrDetail(Long id) {
|
||||||
|
SysLog sysLog = logRepository.findById(id).orElseGet(SysLog::new);
|
||||||
|
ValidationUtil.isNull(sysLog.getId(), "Log", "id", id);
|
||||||
|
byte[] details = sysLog.getExceptionDetail();
|
||||||
|
return Dict.create().set("exception", new String(ObjectUtil.isNotNull(details) ? details : "".getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void download(List<SysLog> sysLogs, HttpServletResponse response) throws IOException {
|
||||||
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
|
for (SysLog sysLog : sysLogs) {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("用户名", sysLog.getUsername());
|
||||||
|
map.put("IP", sysLog.getRequestIp());
|
||||||
|
map.put("IP来源", sysLog.getAddress());
|
||||||
|
map.put("描述", sysLog.getDescription());
|
||||||
|
map.put("浏览器", sysLog.getBrowser());
|
||||||
|
map.put("请求耗时/毫秒", sysLog.getTime());
|
||||||
|
map.put("异常详情", new String(ObjectUtil.isNotNull(sysLog.getExceptionDetail()) ? sysLog.getExceptionDetail() : "".getBytes()));
|
||||||
|
map.put("创建日期", sysLog.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.SysLog;
|
||||||
|
import me.zhengjie.service.dto.SysLogErrorDto;
|
||||||
|
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<SysLogErrorDto, SysLog> {
|
||||||
|
|
||||||
|
}
|
|
@ -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.SysLog;
|
||||||
|
import me.zhengjie.service.dto.SysLogSmallDto;
|
||||||
|
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<SysLogSmallDto, SysLog> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?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.7</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>eladmin-system</artifactId>
|
||||||
|
<name>核心模块</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<jjwt.version>0.11.5</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.7</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.7</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.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<!-- 跳过单元测试 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skipTests>true</skipTests>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -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;
|
||||||
|
|
||||||
|
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.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,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019-2023 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.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,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;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue