Compare commits

..

No commits in common. "main" and "master" have entirely different histories.
main ... master

643 changed files with 49006 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
### IDEA ###
.idea/*
*.iml
*/target/*
*/*.iml
/.gradle/
/application.pid
/.jpb/

191
LICENSE Normal file
View File

@ -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.

1
README.md Normal file
View File

@ -0,0 +1 @@
先运行sql/finance.sql

26
eladmin-common/pom.xml Normal file
View File

@ -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>

View File

@ -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 {
}

View File

@ -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 "";
}

View File

@ -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;
}

View File

@ -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;
/**
* Userdept
*/
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
}
}

View File

@ -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 {};
}

View File

@ -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 {};
}

View File

@ -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 {};
}

View File

@ -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 {};
}

View File

@ -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 {};
}

View File

@ -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;";
}
}

View File

@ -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
}

View File

@ -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 2019102420: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();
}
}

View File

@ -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 2019102420: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();
}
}

View File

@ -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> {
/**
* DTOEntity
* @param dto /
* @return /
*/
E toEntity(D dto);
/**
* EntityDTO
* @param entity /
* @return /
*/
D toDto(E entity);
/**
* DTOEntity
* @param dtoList /
* @return /
*/
List <E> toEntity(List<D> dtoList);
/**
* EntityDTO
* @param entityList /
* @return /
*/
List <D> toDto(List<E> entityList);
}

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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 handleCacheGetErrorkey -> [{}]", key, e);
}
@Override
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
log.error("Redis occur handleCachePutErrorkey -> [{}]value -> [{}]", key, value, e);
}
@Override
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
log.error("Redis occur handleCacheEvictErrorkey -> [{}]", 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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
/**
* Pageableswagger
*/
@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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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";
}
}

View File

@ -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";
}
}

View File

@ -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;
}
}

View File

@ -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()));
}
}

View File

@ -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:";
}

View File

@ -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();
}
}

View File

@ -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) {
// 静默关闭
}
}
}
}

View File

@ -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));
}
}

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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 = "其他";
/**
* MultipartFileFile
*/
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));
}
}

View 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;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.zhengjie.utils;
import org.springframework.data.domain.Page;
import java.util.*;
/**
*
* @author Zheng Jie
* @date 2018-12-10
*/
public class PageUtil extends cn.hutool.core.util.PageUtil {
/**
* List
*/
public static <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);
}
}

View File

@ -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;
}
}

View File

@ -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 () time0 time0 :
* @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=============================
/**
* keySet
*
* @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;
}
}
/**
* valueset,
*
* @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;
}
}
/**
* Nvalue
*
* @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("--------------------------------------------");
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
/**
* applicationContextBean, .
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* applicationContextBean, .
*/
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.");
}
}
/**
* SpringContextHolderApplicationContextNull.
*/
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)));
}
}

View File

@ -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 "";
}
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}
}

View File

@ -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));
}
}

View File

@ -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()));
}
}

39
eladmin-generator/pom.xml Normal file
View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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("打包失败");
}
}
}

View File

@ -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;
/**
* sqljava
*
* @author Zheng Jie
* @date 2019-01-03
*/
public class ColUtil {
private static final Logger log = LoggerFactory.getLogger(ColUtil.class);
/**
* mysqljava
*
* @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;
}
}

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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>
}

View File

@ -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));
}
}

View File

@ -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}> {
}

View File

@ -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>
}

View File

@ -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>
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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 }

View File

@ -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>

22
eladmin-logging/pom.xml Normal file
View File

@ -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>

View File

@ -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 "";
}

View File

@ -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 "";
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");
}
}

View File

@ -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> {
}

View File

@ -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> {
}

108
eladmin-system/pom.xml Normal file
View File

@ -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>

View File

@ -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 添加文件路径,方便 killkill `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";
}
}

View File

@ -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);
}
}

View File

@ -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", "[]{}");
}
}

View File

@ -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();
}
}

View File

@ -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 2019103114: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