diff --git a/UI source code/dns-dev-2.0/.gitignore b/UI source code/dns-dev-2.0/.gitignore
new file mode 100644
index 0000000..9acb04a
--- /dev/null
+++ b/UI source code/dns-dev-2.0/.gitignore
@@ -0,0 +1,7 @@
+### IDEA ###
+.idea/*
+*.iml
+*/target/*
+*/*.iml
+/.gradle/
+/application.pid
\ No newline at end of file
diff --git a/UI source code/dns-dev-2.0/LICENSE b/UI source code/dns-dev-2.0/LICENSE
new file mode 100644
index 0000000..ca38718
--- /dev/null
+++ b/UI source code/dns-dev-2.0/LICENSE
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "{}" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright 2019-2020 Zheng Jie
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/UI source code/dns-dev-2.0/README.md b/UI source code/dns-dev-2.0/README.md
new file mode 100644
index 0000000..6284064
--- /dev/null
+++ b/UI source code/dns-dev-2.0/README.md
@@ -0,0 +1,72 @@
+
DiamondV
+
+
+
+#### 项目简介
+
+一个基于 Spring Boot 2.1.0 、 Spring Boot Jpa、mybatis-plus、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统
+
+**账号密码:** `admin / 123456`
+
+**打包:** `mvn clean install`
+
+#### 项目源码
+
+| | 后端源码 | 前端源码 |
+| ---- | ------------------------------ | ----------------------------------------- |
+| 地址 | http://192.168.40.125/kjch/dns | http://192.168.40.125/kjch/dns_mapping_ui |
+
+#### 主要特性
+
+- 使用最新技术栈,社区资源丰富。
+- 高效率开发,代码生成器可一键生成前后端代码
+- 支持数据字典,可方便地对一些状态进行管理
+- 支持接口限流,避免恶意请求导致服务层压力过大
+- 支持接口级别的功能权限与数据权限,可自定义操作
+- 自定义权限注解与匿名接口注解,可快速对接口拦截与放行
+- 对一些常用地前端组件封装:表格数据请求、数据字典等
+- 前后端统一异常拦截处理,统一输出异常,避免繁琐的判断
+- 支持在线用户管理与服务器性能监控,支持限制单用户登录
+- 支持运维管理,可方便地对远程服务器的应用进行部署与管理
+
+#### 系统功能
+
+- 用户管理:提供用户的相关配置,新增用户后,默认密码为123456
+- 角色管理:对权限与菜单进行分配,可根据部门设置角色的数据权限
+- 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单
+- 部门管理:可配置系统组织架构,树形表格展示
+- 岗位管理:配置各个部门的职位
+- 字典管理:可维护常用一些固定的数据,如:状态,性别等
+- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错
+- SQL监控:采用druid 监控数据库访问性能,默认用户名admin,密码123456
+- 定时任务:整合Quartz做定时任务,加入任务日志,任务运行情况一目了然
+- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
+- 邮件工具:配合富文本,发送html格式的邮件
+- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
+- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
+- 服务监控:监控服务器的负载情况
+- 运维管理:一键部署你的应用
+
+#### 项目结构
+
+项目采用按功能分模块的开发方式,结构如下
+
+- `dns-common` 为系统的公共模块,各种工具类,公共配置存在该模块
+- `dns-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
+- `dns-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块
+- 详细结构
+
+```
+- dns-common 公共模块
+ - annotation 为系统自定义注解
+ - aspect 自定义注解的切面
+ - base 提供了Entity、DTO基类和mapstruct的通用mapper
+ - config 自定义权限实现、redis配置、swagger配置、Rsa配置等
+ - exception 项目统一异常的处理
+ - utils 系统通用工具类
+- dns-system 系统核心模块(系统启动入口)
+ - config 配置跨域与静态资源,与数据权限
+ - thread 线程池相关
+ - modules 系统相关模块(登录授权、系统监控、定时任务、运维管理,测绘等)
+- dns-logging 系统日志模块
+```
diff --git a/UI source code/dns-dev-2.0/dns-common/pom.xml b/UI source code/dns-dev-2.0/dns-common/pom.xml
new file mode 100644
index 0000000..33734bb
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/pom.xml
@@ -0,0 +1,26 @@
+
+
+
+ dns
+ com.example
+ 2.6
+
+ 4.0.0
+
+ 5.3.4
+
+
+ dns-common
+ dns-common
+
+
+
+
+ cn.hutool
+ hutool-all
+ ${hutool.version}
+
+
+
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/AnonymousAccess.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/AnonymousAccess.java
new file mode 100644
index 0000000..9cffb51
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/AnonymousAccess.java
@@ -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 com.example.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author jacky
+ * 用于标记匿名访问方法
+ */
+@Inherited
+@Documented
+@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnonymousAccess {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/DataPermission.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/DataPermission.java
new file mode 100644
index 0000000..7fa3e3f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/DataPermission.java
@@ -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 com.example.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * 用于判断是否过滤数据权限
+ * 1、如果没有用到 @OneToOne 这种关联关系,只需要填写 fieldName [参考:DeptQueryCriteria.class]
+ * 2、如果用到了 @OneToOne ,fieldName 和 joinName 都需要填写,拿UserQueryCriteria.class举例:
+ * 应该是 @DataPermission(joinName = "dept", fieldName = "id")
+ *
+ *
+ * @website https://el-admin.vip
+ * 2020-05-07
+ **/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DataPermission {
+
+ /**
+ * Entity 中的字段名称
+ */
+ String fieldName() default "";
+
+ /**
+ * Entity 中与部门关联的字段名称
+ */
+ String joinName() default "";
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Limit.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Limit.java
new file mode 100644
index 0000000..ee285de
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Limit.java
@@ -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 com.example.annotation;
+
+import com.example.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;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Query.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Query.java
new file mode 100644
index 0000000..e21d60b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Query.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Query {
+
+ // Dong ZhaoYang 2017/8/7 基本对象的属性名
+ String propName() default "";
+ // Dong ZhaoYang 2017/8/7 查询方式
+ Type type() default Type.EQUAL;
+
+ /**
+ * 连接查询的属性名,如User类中的dept
+ */
+ String joinName() default "";
+
+ /**
+ * 默认左连接
+ */
+ Join join() default Join.LEFT;
+
+ /**
+ * 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username")
+ */
+ String blurry() default "";
+
+ enum Type {
+ // jie 2019/6/4 相等
+ EQUAL
+ // Dong ZhaoYang 2017/8/7 大于等于
+ , GREATER_THAN
+ // Dong ZhaoYang 2017/8/7 小于等于
+ , LESS_THAN
+ // Dong ZhaoYang 2017/8/7 中模糊查询
+ , INNER_LIKE
+ // Dong ZhaoYang 2017/8/7 左模糊查询
+ , LEFT_LIKE
+ // Dong ZhaoYang 2017/8/7 右模糊查询
+ , RIGHT_LIKE
+ // Dong ZhaoYang 2017/8/7 小于
+ , LESS_THAN_NQ
+ // jie 2019/6/4 包含
+ , IN
+ // 不包含
+ , NOT_IN
+ // 不等于
+ ,NOT_EQUAL
+ // between
+ ,BETWEEN
+ // 不为空
+ ,NOT_NULL
+ // 为空
+ ,IS_NULL
+ }
+
+ /**
+ *
+ * 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询
+ */
+ enum Join {
+ /** jie 2019-6-4 13:18:30 */
+ LEFT, RIGHT, INNER
+ }
+
+}
+
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousDeleteMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousDeleteMapping.java
new file mode 100644
index 0000000..10fbef4
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousDeleteMapping.java
@@ -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 com.example.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 com.example.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 {};
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousGetMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousGetMapping.java
new file mode 100644
index 0000000..85d6a78
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousGetMapping.java
@@ -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 com.example.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 com.example.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.
+ *
+ * 支持匿名访问 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 {};
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPatchMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPatchMapping.java
new file mode 100644
index 0000000..3281a3b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPatchMapping.java
@@ -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 com.example.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 com.example.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 {};
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPostMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPostMapping.java
new file mode 100644
index 0000000..977de6c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPostMapping.java
@@ -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 com.example.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 com.example.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 {};
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPutMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPutMapping.java
new file mode 100644
index 0000000..6fc00b2
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPutMapping.java
@@ -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 com.example.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 com.example.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 {};
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitAspect.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitAspect.java
new file mode 100644
index 0000000..1e1856d
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitAspect.java
@@ -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 com.example.aspect;
+
+import com.google.common.collect.ImmutableList;
+import com.example.annotation.Limit;
+import com.example.exception.BadRequestException;
+import com.example.utils.RequestHolder;
+import com.example.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 redisTemplate;
+ private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class);
+
+ public LimitAspect(RedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ @Pointcut("@annotation(com.example.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 keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replace("/","_")));
+
+ String luaScript = buildLuaScript();
+ RedisScript 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;";
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitType.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitType.java
new file mode 100644
index 0000000..0a6deb6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitType.java
@@ -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 com.example.aspect;
+
+/**
+ * 限流枚举
+ * @author /
+ */
+public enum LimitType {
+ // 默认
+ CUSTOMER,
+ // by ip addr
+ IP
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseDTO.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseDTO.java
new file mode 100644
index 0000000..7802007
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseDTO.java
@@ -0,0 +1,40 @@
+package com.example.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;
+
+/**
+ *
+ * 2019年10月24日20:48:53
+ */
+@Getter
+@Setter
+public class BaseDTO implements Serializable {
+
+ private String createBy;
+
+ private String updateBy;
+
+ private Timestamp createTime;
+
+ private Timestamp updateTime;
+
+ @Override
+ public String toString() {
+ ToStringBuilder builder = new ToStringBuilder(this);
+ Field[] fields = this.getClass().getDeclaredFields();
+ try {
+ for (Field f : fields) {
+ f.setAccessible(true);
+ builder.append(f.getName(), f.get(this)).append("\n");
+ }
+ } catch (Exception e) {
+ builder.append("toString builder encounter an error");
+ }
+ return builder.toString();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseEntity.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseEntity.java
new file mode 100644
index 0000000..ba31ddf
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseEntity.java
@@ -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 com.example.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 根据需求自行添加
+ *
+ * @Date 2019年10月24日20:46:32
+ */
+@Getter
+@Setter
+@MappedSuperclass
+@EntityListeners(AuditingEntityListener.class)
+public class BaseEntity implements Serializable {
+
+ @CreatedBy
+ @Column(name = "create_by", updatable = false)
+ @ApiModelProperty(value = "创建人", hidden = true)
+ private String createBy;
+
+ @LastModifiedBy
+ @Column(name = "update_by")
+ @ApiModelProperty(value = "更新人", hidden = true)
+ private String updateBy;
+
+ @CreationTimestamp
+ @Column(name = "create_time", updatable = false)
+ @ApiModelProperty(value = "创建时间", hidden = true)
+ private Timestamp createTime;
+
+ @UpdateTimestamp
+ @Column(name = "update_time")
+ @ApiModelProperty(value = "更新时间", hidden = true)
+ private Timestamp updateTime;
+
+ /* 分组校验 */
+ public @interface Create {}
+
+ /* 分组校验 */
+ public @interface Update {}
+
+ @Override
+ public String toString() {
+ ToStringBuilder builder = new ToStringBuilder(this);
+ Field[] fields = this.getClass().getDeclaredFields();
+ try {
+ for (Field f : fields) {
+ f.setAccessible(true);
+ builder.append(f.getName(), f.get(this)).append("\n");
+ }
+ } catch (Exception e) {
+ builder.append("toString builder encounter an error");
+ }
+ return builder.toString();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseMapper.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseMapper.java
new file mode 100644
index 0000000..1c2d38a
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseMapper.java
@@ -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 com.example.base;
+
+import java.util.List;
+
+
+public interface BaseMapper {
+
+ /**
+ * DTO转Entity
+ * @param dto /
+ * @return /
+ */
+ E toEntity(D dto);
+
+ /**
+ * Entity转DTO
+ * @param entity /
+ * @return /
+ */
+ D toDto(E entity);
+
+ /**
+ * DTO集合转Entity集合
+ * @param dtoList /
+ * @return /
+ */
+ List toEntity(List dtoList);
+
+ /**
+ * Entity集合转DTO集合
+ * @param entityList /
+ * @return /
+ */
+ List toDto(List entityList);
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/AuditorConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/AuditorConfig.java
new file mode 100644
index 0000000..7d1dcbe
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/AuditorConfig.java
@@ -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 com.example.config;
+
+import com.example.utils.SecurityUtils;
+import org.springframework.data.domain.AuditorAware;
+import org.springframework.stereotype.Component;
+import java.util.Optional;
+
+/**
+ * @description : 设置审计
+ * @author : Dong ZhaoYang
+ * : 2019/10/28
+ */
+@Component("auditorAware")
+public class AuditorConfig implements AuditorAware {
+
+ /**
+ * 返回操作员标志信息
+ *
+ * @return /
+ */
+ @Override
+ public Optional getCurrentAuditor() {
+ try {
+ // 这里应根据实际业务情况获取具体信息
+ return Optional.of(SecurityUtils.getCurrentUsername());
+ }catch (Exception ignored){}
+ // 用户定时任务,或者无Token调用的情况
+ return Optional.of("System");
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElAdminProperties.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElAdminProperties.java
new file mode 100644
index 0000000..b7670b3
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElAdminProperties.java
@@ -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 com.example.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * @description
+ * 2021-11-22
+ **/
+@Data
+@Component
+public class ElAdminProperties {
+
+ public static Boolean ipLocal;
+
+ @Value("${ip.local-parsing}")
+ public void setIpLocal(Boolean ipLocal) {
+ ElAdminProperties.ipLocal = ipLocal;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElPermissionConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElPermissionConfig.java
new file mode 100644
index 0000000..7b7c1e7
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElPermissionConfig.java
@@ -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 com.example.config;
+
+import com.example.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;
+
+/**
+ *
+ */
+@Service(value = "el")
+public class ElPermissionConfig {
+
+ public Boolean check(String ...permissions){
+ // 获取当前用户的所有权限
+ List elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
+ // 判断当前用户的所有权限是否包含接口上定义的权限
+ return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/FileProperties.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/FileProperties.java
new file mode 100644
index 0000000..a1c3aff
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/FileProperties.java
@@ -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 com.example.config;
+
+import lombok.Data;
+import com.example.utils.ElAdminConstant;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ *
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "file")
+public class FileProperties {
+
+ /** 文件大小限制 */
+ private Long maxSize;
+
+ /** 头像大小限制 */
+ private Long avatarMaxSize;
+
+ private ElPath mac;
+
+ private ElPath linux;
+
+ private ElPath windows;
+
+ public ElPath getPath(){
+ String os = System.getProperty("os.name");
+ if(os.toLowerCase().startsWith(ElAdminConstant.WIN)) {
+ return windows;
+ } else if(os.toLowerCase().startsWith(ElAdminConstant.MAC)){
+ return mac;
+ }
+ return linux;
+ }
+
+ @Data
+ public static class ElPath{
+
+ private String path;
+
+ private String avatar;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RedisConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RedisConfig.java
new file mode 100644
index 0000000..d482e83
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RedisConfig.java
@@ -0,0 +1,217 @@
+/*
+ * 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 com.example.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;
+
+
+/**
+ *
+ * 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 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 redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+ RedisTemplate template = new RedisTemplate<>();
+ //序列化
+ FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
+ // value值的序列化采用fastJsonRedisSerializer
+ template.setValueSerializer(fastJsonRedisSerializer);
+ template.setHashValueSerializer(fastJsonRedisSerializer);
+ // 全局开启AutoType,这里方便开发,使用全局的方式
+ ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
+ // 建议使用这种方式,小范围指定白名单
+ // ParserConfig.getGlobalInstance().addAccept("com.example.domain");
+ // 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 container = new HashMap<>(4);
+ Class> targetClassClass = target.getClass();
+ // 类地址
+ container.put("class",targetClassClass.toGenericString());
+ // 方法名称
+ container.put("methodName",method.getName());
+ // 包名称
+ container.put("package",targetClassClass.getPackage());
+ // 参数列表
+ for (int i = 0; i < params.length; i++) {
+ container.put(String.valueOf(i),params[i]);
+ }
+ // 转为JSON字符串
+ String jsonString = JSON.toJSONString(container);
+ // 做SHA256 Hash计算,得到一个SHA256摘要作为Key
+ return DigestUtils.sha256Hex(jsonString);
+ };
+ }
+
+ @Bean
+ @Override
+ public CacheErrorHandler errorHandler() {
+ // 异常处理,当Redis发生异常时,打印日志,但是程序正常走
+ log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
+ return new CacheErrorHandler() {
+ @Override
+ public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
+ log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
+ }
+
+ @Override
+ public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
+ log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
+ }
+
+ @Override
+ public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
+ log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
+ }
+
+ @Override
+ public void handleCacheClearError(RuntimeException e, Cache cache) {
+ log.error("Redis occur handleCacheClearError:", e);
+ }
+ };
+ }
+
+}
+
+/**
+ * Value 序列化
+ *
+ * @author /
+ * @param
+ */
+ class FastJsonRedisSerializer implements RedisSerializer {
+
+ private final Class clazz;
+
+ FastJsonRedisSerializer(Class 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 {
+
+ 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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RsaProperties.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RsaProperties.java
new file mode 100644
index 0000000..7490f71
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RsaProperties.java
@@ -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 com.example.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * @website https://el-admin.vip
+ * @description
+ * 2020-05-18
+ **/
+@Data
+@Component
+public class RsaProperties {
+
+ public static String privateKey;
+
+ @Value("${rsa.private_key}")
+ public void setPrivateKey(String privateKey) {
+ RsaProperties.privateKey = privateKey;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/SwaggerConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/SwaggerConfig.java
new file mode 100644
index 0000000..7d0b1c6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/SwaggerConfig.java
@@ -0,0 +1,148 @@
+/*
+ * 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 com.example.config;
+
+import com.fasterxml.classmate.TypeResolver;
+import com.google.common.base.Predicates;
+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.*;
+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 com.google.common.collect.Lists.newArrayList;
+import static springfox.documentation.schema.AlternateTypeRules.newRule;
+
+/**
+ * api页面 /doc.html
+ *
+ * 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(Predicates.not(PathSelectors.regex("/error.*")))
+ .paths(PathSelectors.any())
+ .build()
+ //添加登陆认证
+ .securitySchemes(securitySchemes())
+ .securityContexts(securityContexts());
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder()
+ .description("一个简单且易上手的 Spring boot 后台管理框架")
+ .title("DNS测绘 接口文档")
+ .version("2.6")
+ .build();
+ }
+
+ private List securitySchemes() {
+ //设置请求头信息
+ List securitySchemes = new ArrayList<>();
+ ApiKey apiKey = new ApiKey(tokenHeader, tokenHeader, "header");
+ securitySchemes.add(apiKey);
+ return securitySchemes;
+ }
+
+ private List securityContexts() {
+ //设置需要登录认证的路径
+ List securityContexts = new ArrayList<>();
+ // ^(?!auth).*$ 表示所有包含auth的接口不需要使用securitySchemes即不需要带token
+ // ^标识开始 ()里是一子表达式 ?!/auth表示匹配不是/auth的位置,匹配上则添加请求头,注意路径已/开头 .表示任意字符 *表示前面的字符匹配多次 $标识结束
+ securityContexts.add(getContextByPath());
+ return securityContexts;
+ }
+
+ private SecurityContext getContextByPath() {
+ return SecurityContext.builder()
+ .securityReferences(defaultAuth())
+ .forPaths(PathSelectors.regex("^(?!/auth).*$"))
+ .build();
+ }
+
+ private List defaultAuth() {
+ List securityReferences = new ArrayList<>();
+ AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+ AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+ authorizationScopes[0] = authorizationScope;
+ securityReferences.add(new SecurityReference(tokenHeader, authorizationScopes));
+ return securityReferences;
+ }
+}
+
+/**
+ * 将Pageable转换展示在swagger中
+ */
+@Configuration
+class SwaggerDataConfig {
+
+ @Bean
+ public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {
+ return new AlternateTypeRuleConvention() {
+ @Override
+ public int getOrder() {
+ return Ordered.HIGHEST_PRECEDENCE;
+ }
+
+ @Override
+ public List rules() {
+ return 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 sort;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadConfigurationException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadConfigurationException.java
new file mode 100644
index 0000000..0ca41ad
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadConfigurationException.java
@@ -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 com.example.exception;
+
+/**
+ * 统一关于错误配置信息 异常
+ *
+ * @author: liaojinlong
+ * : 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. Note that the detail message associated with
+ * {@code cause} is not 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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadRequestException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadRequestException.java
new file mode 100644
index 0000000..e8c7474
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadRequestException.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.example.exception;
+
+import lombok.Getter;
+import org.springframework.http.HttpStatus;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+
+@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();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityExistException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityExistException.java
new file mode 100644
index 0000000..5af387f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityExistException.java
@@ -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 com.example.exception;
+
+import org.springframework.util.StringUtils;
+
+
+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";
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityNotFoundException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityNotFoundException.java
new file mode 100644
index 0000000..cdfd771
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityNotFoundException.java
@@ -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 com.example.exception;
+
+import org.springframework.util.StringUtils;
+
+
+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";
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/ApiError.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/ApiError.java
new file mode 100644
index 0000000..82ec628
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/ApiError.java
@@ -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 com.example.exception.handler;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import java.time.LocalDateTime;
+
+
+@Data
+class ApiError {
+
+ private Integer status = 400;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime timestamp;
+ private String message;
+
+ private ApiError() {
+ timestamp = LocalDateTime.now();
+ }
+
+ public static ApiError error(String message){
+ ApiError apiError = new ApiError();
+ apiError.setMessage(message);
+ return apiError;
+ }
+
+ public static ApiError error(Integer status, String message){
+ ApiError apiError = new ApiError();
+ apiError.setStatus(status);
+ apiError.setMessage(message);
+ return apiError;
+ }
+}
+
+
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/GlobalExceptionHandler.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/GlobalExceptionHandler.java
new file mode 100644
index 0000000..ba044d1
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/GlobalExceptionHandler.java
@@ -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 com.example.exception.handler;
+
+import com.example.exception.BadRequestException;
+import com.example.exception.EntityExistException;
+import com.example.exception.EntityNotFoundException;
+import com.example.utils.ThrowableUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import java.util.Objects;
+import static org.springframework.http.HttpStatus.*;
+
+
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ /**
+ * 处理所有不可知的异常
+ */
+ @ExceptionHandler(Throwable.class)
+ public ResponseEntity handleException(Throwable e){
+ // 打印堆栈信息
+ log.error(ThrowableUtil.getStackTrace(e));
+ return buildResponseEntity(ApiError.error(e.getMessage()));
+ }
+
+ /**
+ * BadCredentialsException
+ */
+ @ExceptionHandler(BadCredentialsException.class)
+ public ResponseEntity badCredentialsException(BadCredentialsException e){
+ // 打印堆栈信息
+ String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage();
+ log.error(message);
+ return buildResponseEntity(ApiError.error(message));
+ }
+
+ /**
+ * 处理自定义异常
+ */
+ @ExceptionHandler(value = BadRequestException.class)
+ public ResponseEntity badRequestException(BadRequestException e) {
+ // 打印堆栈信息
+ log.error(ThrowableUtil.getStackTrace(e));
+ return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage()));
+ }
+
+ /**
+ * 处理 EntityExist
+ */
+ @ExceptionHandler(value = EntityExistException.class)
+ public ResponseEntity entityExistException(EntityExistException e) {
+ // 打印堆栈信息
+ log.error(ThrowableUtil.getStackTrace(e));
+ return buildResponseEntity(ApiError.error(e.getMessage()));
+ }
+
+ /**
+ * 处理 EntityNotFound
+ */
+ @ExceptionHandler(value = EntityNotFoundException.class)
+ public ResponseEntity entityNotFoundException(EntityNotFoundException e) {
+ // 打印堆栈信息
+ log.error(ThrowableUtil.getStackTrace(e));
+ return buildResponseEntity(ApiError.error(NOT_FOUND.value(),e.getMessage()));
+ }
+
+ /**
+ * 处理所有接口数据验证异常
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
+ // 打印堆栈信息
+ log.error(ThrowableUtil.getStackTrace(e));
+ String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\.");
+ String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
+ String msg = "不能为空";
+ if(msg.equals(message)){
+ message = str[1] + ":" + message;
+ }
+ return buildResponseEntity(ApiError.error(message));
+ }
+
+ /**
+ * 统一返回
+ */
+ private ResponseEntity buildResponseEntity(ApiError apiError) {
+ return new ResponseEntity<>(apiError, valueOf(apiError.getStatus()));
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CacheKey.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CacheKey.java
new file mode 100644
index 0000000..8e93877
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CacheKey.java
@@ -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 com.example.utils;
+
+/**
+ * @author: liaojinlong
+ * : 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:";
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CallBack.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CallBack.java
new file mode 100644
index 0000000..59a7d0b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CallBack.java
@@ -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 com.example.utils;
+
+/**
+ * @author: liaojinlong
+ * : 2020/6/9 17:02
+ * @since: 1.0
+ * @see {@link SpringContextHolder}
+ * 针对某些初始化方法,在SpringContextHolder 初始化前时,
+ * 可提交一个 提交回调任务。
+ * 在SpringContextHolder 初始化后,进行回调使用
+ */
+
+public interface CallBack {
+ /**
+ * 回调执行方法
+ */
+ void executor();
+
+ /**
+ * 本回调任务名称
+ * @return /
+ */
+ default String getCallBackName() {
+ return Thread.currentThread().getId() + ":" + this.getClass().getName();
+ }
+}
+
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CloseUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CloseUtil.java
new file mode 100644
index 0000000..cd515bc
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CloseUtil.java
@@ -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 com.example.utils;
+
+import java.io.Closeable;
+
+/**
+ *
+ * @website https://el-admin.vip
+ * @description 用于关闭各种连接,缺啥补啥
+ * 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) {
+ // 静默关闭
+ }
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/Constant.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/Constant.java
new file mode 100644
index 0000000..402403e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/Constant.java
@@ -0,0 +1,62 @@
+package com.example.utils;
+
+/**
+ * 常量
+ */
+public class Constant {
+ public static final String DOH = "dns-doh";
+
+ public static final String DO53 = "dns-do53";
+
+ public static final String SERVICE = "service";
+
+ public static final String IP = "ip";
+
+ public static final String PORT = "port";
+
+ public static final Integer NONE = 0;
+
+ public static final Integer OPENRDNS = 1;
+
+ public static final Integer FORWARDER = 2;
+
+ public static final Integer FWDRDNS = 3;
+
+ public static final Integer EGRESSRDNS = 4;
+
+ public static final Integer NONSTANDARD = 5;
+
+ public static final String PORT8443 = "8443";
+
+ public static final String PORT443 = "443";
+
+ public static final String PORT53 = "53";
+
+ public static final String DNSTAG = "dns";
+
+ public static final String DOHTAG = "DNS-DoH";
+
+ public static final String DO53TAG = "DNS-Do53";
+
+ public static final String OPENRDNSTAG = "open-rdns";
+
+ public static final String FORWARDERTAG = "forwarder";
+
+ public static final String FWDRDNSTAG = "fwd/rdns";
+
+ public static final String EGRESSRDNSTAG = "egress-dns";
+
+ public static final String NONSTANDARDTAG = "nonstandard";
+
+ public static final String PROTOC_TCP = "tcp";
+
+ public static final String PROTOC_UDP = "udp";
+
+ public static final String IP_IPV4 = "ipv4";
+
+ public static final String IP_IPV6 = "ipv6";
+
+ public static final String POINT = ".";
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/DateUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/DateUtil.java
new file mode 100644
index 0000000..57e9408
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/DateUtil.java
@@ -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 com.example.utils;
+
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+/**
+ * @author: liaojinlong
+ * : 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));
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ElAdminConstant.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ElAdminConstant.java
new file mode 100644
index 0000000..f46ff3b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ElAdminConstant.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.example.utils;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 常用静态常量
+ *
+ *
+ * 2018-12-26
+ */
+public class ElAdminConstant {
+
+ private ElAdminConstant() {
+ throw new IllegalStateException("Utility class");
+ }
+
+ /**
+ * 用于IP定位转换
+ */
+ public static final String REGION = "内网IP|内网IP";
+ /**
+ * win 系统
+ */
+ public static final String WIN = "win";
+
+ /**
+ * mac 系统
+ */
+ public static final String MAC = "mac";
+
+ public static final List openRdnsLabels = Arrays.asList("DNS", "DNS-Do53", "open-rdns");
+
+ public static final List forwarderLabels = Arrays.asList("DNS", "DNS-Do53", "forwarder");
+
+ public static final List fwdRdnsLabels = Arrays.asList("DNS", "DNS-Do53", "fwd/rdns");
+
+ public static final List egressDnsLabels = Arrays.asList("DNS", "DNS-Do53", "egress-dns");
+
+ public static final List nonstandardLabels = Arrays.asList("DNS", "DNS-Do53", "nonstandard");
+
+ public static final List dnsLabels = Arrays.asList("DNS");
+
+ public static final List dohLabels = Arrays.asList("DNS","DNS-DoH");
+
+ public static final List do53Labels = Arrays.asList(new String[]{"DNS","DNS-Do53"});
+
+ /**
+ * 常用接口
+ */
+ public static class Url {
+ // IP归属地查询
+ public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?ip=%s&json=true";
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/EncryptUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/EncryptUtils.java
new file mode 100644
index 0000000..6ee5a49
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/EncryptUtils.java
@@ -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 com.example.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;
+
+/**
+ * 加密
+ *
+ * 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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/FileUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/FileUtil.java
new file mode 100644
index 0000000..dc209a9
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/FileUtil.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.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 com.example.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 工具包
+ *
+ *
+ * 2018-12-27
+ */
+public class FileUtil extends cn.hutool.core.io.FileUtil {
+
+ private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
+
+ /**
+ * 系统临时目录
+ *
+ * windows 包含路径分割符,但Linux 不包含,
+ * 在windows \\==\ 前提下,
+ * 为安全起见 同意拼装 路径分割符,
+ *
+ * java.io.tmpdir
+ * windows : C:\Users/xxx\AppData\Local\Temp\
+ * linux: /temp
+ *
+ */
+ public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
+ /**
+ * 定义GB的计算常量
+ */
+ private static final int GB = 1024 * 1024 * 1024;
+ /**
+ * 定义MB的计算常量
+ */
+ private static final int MB = 1024 * 1024;
+ /**
+ * 定义KB的计算常量
+ */
+ private static final int KB = 1024;
+
+ /**
+ * 格式化小数
+ */
+ private static final DecimalFormat DF = new DecimalFormat("0.00");
+
+ public static final String IMAGE = "图片";
+ public static final String TXT = "文档";
+ public static final String MUSIC = "音乐";
+ public static final String VIDEO = "视频";
+ public static final String OTHER = "其他";
+
+
+ /**
+ * MultipartFile转File
+ */
+ public static File toFile(MultipartFile multipartFile) {
+ // 获取文件名
+ String fileName = multipartFile.getOriginalFilename();
+ // 获取文件后缀
+ String prefix = "." + getExtensionName(fileName);
+ File file = null;
+ try {
+ // 用uuid作为文件名,防止生成的临时文件重复
+ file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix);
+ // MultipartFile to File
+ multipartFile.transferTo(file);
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ return file;
+ }
+
+ /**
+ * 获取文件扩展名,不带 .
+ */
+ public static String getExtensionName(String filename) {
+ if ((filename != null) && (filename.length() > 0)) {
+ int dot = filename.lastIndexOf('.');
+ if ((dot > -1) && (dot < (filename.length() - 1))) {
+ return filename.substring(dot + 1);
+ }
+ }
+ return filename;
+ }
+
+ /**
+ * Java文件操作 获取不带扩展名的文件名
+ */
+ public static String getFileNameNoEx(String filename) {
+ if ((filename != null) && (filename.length() > 0)) {
+ int dot = filename.lastIndexOf('.');
+ if ((dot > -1) && (dot < (filename.length()))) {
+ return filename.substring(0, dot);
+ }
+ }
+ return filename;
+ }
+
+ /**
+ * 文件大小转换
+ */
+ public static String getSize(long size) {
+ String resultSize;
+ if (size / GB >= 1) {
+ //如果当前Byte的值大于等于1GB
+ resultSize = DF.format(size / (float) GB) + "GB ";
+ } else if (size / MB >= 1) {
+ //如果当前Byte的值大于等于1MB
+ resultSize = DF.format(size / (float) MB) + "MB ";
+ } else if (size / KB >= 1) {
+ //如果当前Byte的值大于等于1KB
+ resultSize = DF.format(size / (float) KB) + "KB ";
+ } else {
+ resultSize = size + "B ";
+ }
+ return resultSize;
+ }
+
+ /**
+ * inputStream 转 File
+ */
+ static File inputStreamToFile(InputStream ins, String name){
+ File file = new File(SYS_TEM_DIR + name);
+ if (file.exists()) {
+ return file;
+ }
+ OutputStream os = null;
+ try {
+ os = new FileOutputStream(file);
+ int bytesRead;
+ int len = 8192;
+ byte[] buffer = new byte[len];
+ while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
+ os.write(buffer, 0, bytesRead);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ CloseUtil.close(os);
+ CloseUtil.close(ins);
+ }
+ return file;
+ }
+
+ /**
+ * 将文件名解析成文件的上传路径
+ */
+ public static File upload(MultipartFile file, String filePath) {
+ Date date = new Date();
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
+ String name = getFileNameNoEx(file.getOriginalFilename());
+ String suffix = getExtensionName(file.getOriginalFilename());
+ String nowStr = "-" + format.format(date);
+ try {
+ String fileName = name + nowStr + "." + suffix;
+ String path = filePath + fileName;
+ // getCanonicalFile 可解析正确各种路径
+ File dest = new File(path).getCanonicalFile();
+ // 检测是否存在目录
+ if (!dest.getParentFile().exists()) {
+ if (!dest.getParentFile().mkdirs()) {
+ System.out.println("was not successful.");
+ }
+ }
+ // 文件写入
+ file.transferTo(dest);
+ return dest;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * 导出excel
+ */
+ public static void downloadExcel(List> list, HttpServletResponse response) throws IOException {
+ String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx";
+ File file = new File(tempPath);
+ BigExcelWriter writer = ExcelUtil.getBigWriter(file);
+ // 一次性写出内容,使用默认样式,强制输出标题
+ writer.write(list, true);
+ SXSSFSheet sheet = (SXSSFSheet)writer.getSheet();
+ //上面需要强转SXSSFSheet 不然没有trackAllColumnsForAutoSizing方法
+ sheet.trackAllColumnsForAutoSizing();
+ //列宽自适应
+ writer.autoSizeColumnAll();
+ //response为HttpServletResponse对象
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
+ //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
+ response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
+ ServletOutputStream out = response.getOutputStream();
+ // 终止后删除临时文件
+ file.deleteOnExit();
+ writer.flush(out, true);
+ //此处记得关闭输出Servlet流
+ IoUtil.close(out);
+ }
+
+ public static String getFileType(String type) {
+ String documents = "txt doc pdf ppt pps xlsx xls docx";
+ String music = "mp3 wav wma mpa ram ra aac aif m4a";
+ String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
+ String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
+ if (image.contains(type)) {
+ return IMAGE;
+ } else if (documents.contains(type)) {
+ return TXT;
+ } else if (music.contains(type)) {
+ return MUSIC;
+ } else if (video.contains(type)) {
+ return VIDEO;
+ } else {
+ return OTHER;
+ }
+ }
+
+ public static void checkSize(long maxSize, long size) {
+ // 1M
+ int len = 1024 * 1024;
+ if (size > (maxSize * len)) {
+ throw new BadRequestException("文件超出规定大小:" + maxSize + "MB");
+ }
+ }
+
+ /**
+ * 判断两个文件是否相同
+ */
+ public static boolean check(File file1, File file2) {
+ String img1Md5 = getMd5(file1);
+ String img2Md5 = getMd5(file2);
+ if(img1Md5 != null){
+ return img1Md5.equals(img2Md5);
+ }
+ return false;
+ }
+
+ /**
+ * 判断两个文件是否相同
+ */
+ public static boolean check(String file1Md5, String file2Md5) {
+ return file1Md5.equals(file2Md5);
+ }
+
+ private static byte[] getByte(File file) {
+ // 得到文件长度
+ byte[] b = new byte[(int) file.length()];
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ try {
+ System.out.println(in.read(b));
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return null;
+ } finally {
+ CloseUtil.close(in);
+ }
+ return b;
+ }
+
+ private static String getMd5(byte[] bytes) {
+ // 16进制字符
+ char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ try {
+ MessageDigest mdTemp = MessageDigest.getInstance("MD5");
+ mdTemp.update(bytes);
+ byte[] md = mdTemp.digest();
+ int j = md.length;
+ char[] str = new char[j * 2];
+ int k = 0;
+ // 移位 输出字符串
+ for (byte byte0 : md) {
+ str[k++] = hexDigits[byte0 >>> 4 & 0xf];
+ str[k++] = hexDigits[byte0 & 0xf];
+ }
+ return new String(str);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * 下载文件
+ *
+ * @param request /
+ * @param response /
+ * @param file /
+ */
+ public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) {
+ response.setCharacterEncoding(request.getCharacterEncoding());
+ response.setContentType("application/octet-stream");
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(file);
+ response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
+ IOUtils.copy(fis, response.getOutputStream());
+ response.flushBuffer();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ if (deleteOnExit) {
+ file.deleteOnExit();
+ }
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ public static String getMd5(File file) {
+ return getMd5(getByte(file));
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/PageUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/PageUtil.java
new file mode 100644
index 0000000..5bea120
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/PageUtil.java
@@ -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 com.example.utils;
+
+import org.springframework.data.domain.Page;
+import java.util.*;
+
+/**
+ * 分页工具
+ *
+ * 2018-12-10
+ */
+public class PageUtil extends cn.hutool.core.util.PageUtil {
+
+ /**
+ * List 分页
+ */
+ public static List toPage(int page, int size , List list) {
+ int fromIndex = page * size;
+ int toIndex = page * size + size;
+ if(fromIndex > list.size()){
+ return new ArrayList();
+ } else if(toIndex >= list.size()) {
+ return list.subList(fromIndex,list.size());
+ } else {
+ return list.subList(fromIndex,toIndex);
+ }
+ }
+
+ /**
+ * Page 数据处理,预防redis反序列化报错
+ */
+ public static Map toPage(Page page) {
+ Map map = new LinkedHashMap<>(2);
+ map.put("content",page.getContent());
+ map.put("totalElements",page.getTotalElements());
+ return map;
+ }
+
+ /**
+ * 自定义分页
+ */
+ public static Map toPage(Object object, Object totalElements) {
+ Map map = new LinkedHashMap<>(2);
+ map.put("content",object);
+ map.put("totalElements",totalElements);
+ return map;
+ }
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/QueryHelp.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/QueryHelp.java
new file mode 100644
index 0000000..e9cf239
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/QueryHelp.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.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 com.example.annotation.DataPermission;
+import com.example.annotation.Query;
+import javax.persistence.criteria.*;
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ *
+ * 2019-6-4 14:59:48
+ */
+@Slf4j
+@SuppressWarnings({"unchecked","all"})
+public class QueryHelp {
+
+ public static Predicate getPredicate(Root root, Q query, CriteriaBuilder cb) {
+ List 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 dataScopes = SecurityUtils.getCurrentUserDataScope();
+ if(CollectionUtil.isNotEmpty(dataScopes)){
+ if(StringUtils.isNotBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) {
+ Join join = root.join(permission.joinName(), JoinType.LEFT);
+ list.add(getExpression(permission.fieldName(),join, root).in(dataScopes));
+ } else if (StringUtils.isBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) {
+ list.add(getExpression(permission.fieldName(),null, root).in(dataScopes));
+ }
+ }
+ }
+ try {
+ List 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 orPredicate = new ArrayList<>();
+ for (String s : blurrys) {
+ orPredicate.add(cb.like(root.get(s)
+ .as(String.class), "%" + val.toString() + "%"));
+ }
+ Predicate[] p = new Predicate[orPredicate.size()];
+ list.add(cb.or(orPredicate.toArray(p)));
+ continue;
+ }
+ if (ObjectUtil.isNotEmpty(joinName)) {
+ String[] joinNames = joinName.split(">");
+ for (String name : joinNames) {
+ switch (q.join()) {
+ case LEFT:
+ if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){
+ join = join.join(name, JoinType.LEFT);
+ } else {
+ join = root.join(name, JoinType.LEFT);
+ }
+ break;
+ case RIGHT:
+ if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){
+ join = join.join(name, JoinType.RIGHT);
+ } else {
+ join = root.join(name, JoinType.RIGHT);
+ }
+ break;
+ case INNER:
+ if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){
+ join = join.join(name, JoinType.INNER);
+ } else {
+ join = root.join(name, JoinType.INNER);
+ }
+ break;
+ default: break;
+ }
+ }
+ }
+ switch (q.type()) {
+ case EQUAL:
+ list.add(cb.equal(getExpression(attributeName,join,root)
+ .as((Class extends Comparable>) fieldType),val));
+ break;
+ case GREATER_THAN:
+ list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root)
+ .as((Class extends Comparable>) fieldType), (Comparable) val));
+ break;
+ case LESS_THAN:
+ list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root)
+ .as((Class extends Comparable>) fieldType), (Comparable) val));
+ break;
+ case LESS_THAN_NQ:
+ list.add(cb.lessThan(getExpression(attributeName,join,root)
+ .as((Class extends Comparable>) fieldType), (Comparable) val));
+ break;
+ case INNER_LIKE:
+ list.add(cb.like(getExpression(attributeName,join,root)
+ .as(String.class), "%" + val.toString() + "%"));
+ break;
+ case LEFT_LIKE:
+ list.add(cb.like(getExpression(attributeName,join,root)
+ .as(String.class), "%" + val.toString()));
+ break;
+ case RIGHT_LIKE:
+ list.add(cb.like(getExpression(attributeName,join,root)
+ .as(String.class), val.toString() + "%"));
+ break;
+ case IN:
+ if (CollUtil.isNotEmpty((Collection)val)) {
+ list.add(getExpression(attributeName,join,root).in((Collection) val));
+ }
+ break;
+ case NOT_IN:
+ if (CollUtil.isNotEmpty((Collection)val)) {
+ list.add(getExpression(attributeName,join,root).in((Collection) 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 between = new ArrayList<>((List)val);
+ list.add(cb.between(getExpression(attributeName, join, root).as((Class extends Comparable>) between.get(0).getClass()),
+ (Comparable) between.get(0), (Comparable) between.get(1)));
+ break;
+ default: break;
+ }
+ }
+ field.setAccessible(accessible);
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ int size = list.size();
+ return cb.and(list.toArray(new Predicate[size]));
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Expression getExpression(String attributeName, Join join, Root 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 getAllFields(Class clazz, List fields) {
+ if (clazz != null) {
+ fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
+ getAllFields(clazz.getSuperclass(), fields);
+ }
+ return fields;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RedisUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RedisUtils.java
new file mode 100644
index 0000000..4de0949
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RedisUtils.java
@@ -0,0 +1,708 @@
+/*
+ * 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 com.example.utils;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.*;
+import org.springframework.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 redisTemplate;
+ @Value("${jwt.online-key}")
+ private String onlineKey;
+
+ public RedisUtils(RedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ /**
+ * 指定缓存失效时间
+ *
+ * @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 scan(String pattern) {
+ ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
+ RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
+ RedisConnection rc = Objects.requireNonNull(factory).getConnection();
+ Cursor cursor = rc.scan(options);
+ List 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 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 cursor = rc.scan(options);
+ List 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 keySet = new HashSet<>();
+ for (String key : keys) {
+ keySet.addAll(redisTemplate.keys(key));
+ }
+ long count = redisTemplate.delete(keySet);
+ log.debug("--------------------------------------------");
+ log.debug("成功删除缓存:" + keySet.toString());
+ log.debug("缓存删除数量:" + count + "个");
+ log.debug("--------------------------------------------");
+ }
+ }
+ }
+
+ // ============================String=============================
+
+ /**
+ * 普通缓存获取
+ *
+ * @param key 键
+ * @return 值
+ */
+ public Object get(String key) {
+ return key == null ? null : redisTemplate.opsForValue().get(key);
+ }
+
+ /**
+ * 批量获取
+ *
+ * @param keys
+ * @return
+ */
+ public List multiGet(List keys) {
+ List list = redisTemplate.opsForValue().multiGet(Sets.newHashSet(keys));
+ List resultList = Lists.newArrayList();
+ Optional.ofNullable(list).ifPresent(e-> list.forEach(ele-> Optional.ofNullable(ele).ifPresent(resultList::add)));
+ return resultList;
+ }
+
+ /**
+ * 普通缓存放入
+ *
+ * @param key 键
+ * @param value 值
+ * @return true成功 false失败
+ */
+ public boolean set(String key, Object value) {
+ try {
+ redisTemplate.opsForValue().set(key, value);
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 普通缓存放入并设置时间
+ *
+ * @param key 键
+ * @param value 值
+ * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
+ * @return true成功 false 失败
+ */
+ public boolean set(String key, Object value, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+ } else {
+ set(key, value);
+ }
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 普通缓存放入并设置时间
+ *
+ * @param key 键
+ * @param value 值
+ * @param time 时间
+ * @param timeUnit 类型
+ * @return true成功 false 失败
+ */
+ public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
+ try {
+ if (time > 0) {
+ redisTemplate.opsForValue().set(key, value, time, timeUnit);
+ } else {
+ set(key, value);
+ }
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ // ================================Map=================================
+
+ /**
+ * HashGet
+ *
+ * @param key 键 不能为null
+ * @param item 项 不能为null
+ * @return 值
+ */
+ public Object hget(String key, String item) {
+ return redisTemplate.opsForHash().get(key, item);
+ }
+
+ /**
+ * 获取hashKey对应的所有键值
+ *
+ * @param key 键
+ * @return 对应的多个键值
+ */
+ public Map hmget(String key) {
+ return redisTemplate.opsForHash().entries(key);
+
+ }
+
+ /**
+ * HashSet
+ *
+ * @param key 键
+ * @param map 对应多个键值
+ * @return true 成功 false 失败
+ */
+ public boolean hmset(String key, Map map) {
+ try {
+ redisTemplate.opsForHash().putAll(key, map);
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * HashSet 并设置时间
+ *
+ * @param key 键
+ * @param map 对应多个键值
+ * @param time 时间(秒)
+ * @return true成功 false失败
+ */
+ public boolean hmset(String key, Map map, long time) {
+ try {
+ redisTemplate.opsForHash().putAll(key, map);
+ if (time > 0) {
+ expire(key, time);
+ }
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 向一张hash表中放入数据,如果不存在将创建
+ *
+ * @param key 键
+ * @param item 项
+ * @param value 值
+ * @return true 成功 false失败
+ */
+ public boolean hset(String key, String item, Object value) {
+ try {
+ redisTemplate.opsForHash().put(key, item, value);
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 向一张hash表中放入数据,如果不存在将创建
+ *
+ * @param key 键
+ * @param item 项
+ * @param value 值
+ * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
+ * @return true 成功 false失败
+ */
+ public boolean hset(String key, String item, Object value, long time) {
+ try {
+ redisTemplate.opsForHash().put(key, item, value);
+ if (time > 0) {
+ expire(key, time);
+ }
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 删除hash表中的值
+ *
+ * @param key 键 不能为null
+ * @param item 项 可以使多个 不能为null
+ */
+ public void hdel(String key, Object... item) {
+ redisTemplate.opsForHash().delete(key, item);
+ }
+
+ /**
+ * 判断hash表中是否有该项的值
+ *
+ * @param key 键 不能为null
+ * @param item 项 不能为null
+ * @return true 存在 false不存在
+ */
+ public boolean hHasKey(String key, String item) {
+ return redisTemplate.opsForHash().hasKey(key, item);
+ }
+
+ /**
+ * hash递增 如果不存在,就会创建一个 并把新增后的值返回
+ *
+ * @param key 键
+ * @param item 项
+ * @param by 要增加几(大于0)
+ * @return
+ */
+ public double hincr(String key, String item, double by) {
+ return redisTemplate.opsForHash().increment(key, item, by);
+ }
+
+ /**
+ * hash递减
+ *
+ * @param key 键
+ * @param item 项
+ * @param by 要减少记(小于0)
+ * @return
+ */
+ public double hdecr(String key, String item, double by) {
+ return redisTemplate.opsForHash().increment(key, item, -by);
+ }
+
+ // ============================set=============================
+
+ /**
+ * 根据key获取Set中的所有值
+ *
+ * @param key 键
+ * @return
+ */
+ public Set sGet(String key) {
+ try {
+ return redisTemplate.opsForSet().members(key);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return null;
+ }
+ }
+
+ /**
+ * 根据value从一个set中查询,是否存在
+ *
+ * @param key 键
+ * @param value 值
+ * @return true 存在 false不存在
+ */
+ public boolean sHasKey(String key, Object value) {
+ try {
+ return redisTemplate.opsForSet().isMember(key, value);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 将数据放入set缓存
+ *
+ * @param key 键
+ * @param values 值 可以是多个
+ * @return 成功个数
+ */
+ public long sSet(String key, Object... values) {
+ try {
+ return redisTemplate.opsForSet().add(key, values);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return 0;
+ }
+ }
+
+ /**
+ * 将set数据放入缓存
+ *
+ * @param key 键
+ * @param time 时间(秒)
+ * @param values 值 可以是多个
+ * @return 成功个数
+ */
+ public long sSetAndTime(String key, long time, Object... values) {
+ try {
+ Long count = redisTemplate.opsForSet().add(key, values);
+ if (time > 0) {
+ expire(key, time);
+ }
+ return count;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return 0;
+ }
+ }
+
+ /**
+ * 获取set缓存的长度
+ *
+ * @param key 键
+ * @return
+ */
+ public long sGetSetSize(String key) {
+ try {
+ return redisTemplate.opsForSet().size(key);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return 0;
+ }
+ }
+
+ /**
+ * 移除值为value的
+ *
+ * @param key 键
+ * @param values 值 可以是多个
+ * @return 移除的个数
+ */
+ public long setRemove(String key, Object... values) {
+ try {
+ Long count = redisTemplate.opsForSet().remove(key, values);
+ return count;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return 0;
+ }
+ }
+
+ // ===============================list=================================
+
+ /**
+ * 获取list缓存的内容
+ *
+ * @param key 键
+ * @param start 开始
+ * @param end 结束 0 到 -1代表所有值
+ * @return
+ */
+ public List 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 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 value, long time) {
+ try {
+ redisTemplate.opsForList().rightPushAll(key, value);
+ if (time > 0) {
+ expire(key, time);
+ }
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 根据索引修改list中的某条数据
+ *
+ * @param key 键
+ * @param index 索引
+ * @param value 值
+ * @return /
+ */
+ public boolean lUpdateIndex(String key, long index, Object value) {
+ try {
+ redisTemplate.opsForList().set(key, index, value);
+ return true;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 移除N个值为value
+ *
+ * @param key 键
+ * @param count 移除多少个
+ * @param value 值
+ * @return 移除的个数
+ */
+ public long lRemove(String key, long count, Object value) {
+ try {
+ return redisTemplate.opsForList().remove(key, count, value);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return 0;
+ }
+ }
+
+ /**
+ * @param prefix 前缀
+ * @param ids id
+ */
+ public void delByKeys(String prefix, Set ids) {
+ Set 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("--------------------------------------------");
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RequestHolder.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RequestHolder.java
new file mode 100644
index 0000000..09764e4
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RequestHolder.java
@@ -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 com.example.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
+ *
+ * 2018-11-24
+ */
+public class RequestHolder {
+
+ public static HttpServletRequest getHttpServletRequest() {
+ return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RsaUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RsaUtils.java
new file mode 100644
index 0000000..4611a15
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RsaUtils.java
@@ -0,0 +1,198 @@
+package com.example.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 工具类,公钥私钥生成,加解密
+ * 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;
+ }
+
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SecurityUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SecurityUtils.java
new file mode 100644
index 0000000..e263130
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SecurityUtils.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.utils;
+
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.example.utils.enums.DataScopeEnum;
+import lombok.extern.slf4j.Slf4j;
+import com.example.exception.BadRequestException;
+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;
+
+/**
+ * 获取当前登录的用户
+ *
+ * 2019-01-17
+ */
+@Slf4j
+public class SecurityUtils {
+
+ /**
+ * 获取当前登录的用户
+ * @return UserDetails
+ */
+ public static UserDetails getCurrentUser() {
+ UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class);
+ return userDetailsService.loadUserByUsername(getCurrentUsername());
+ }
+
+ /**
+ * 获取系统用户名称
+ *
+ * @return 系统用户名称
+ */
+ public static String getCurrentUsername() {
+ final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");
+ }
+ if (authentication.getPrincipal() instanceof UserDetails) {
+ UserDetails userDetails = (UserDetails) authentication.getPrincipal();
+ return userDetails.getUsername();
+ }
+ throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");
+ }
+
+ /**
+ * 获取系统用户ID
+ * @return 系统用户ID
+ */
+ public static Long getCurrentUserId() {
+ UserDetails userDetails = getCurrentUser();
+ return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class);
+ }
+
+ /**
+ * 获取当前用户的数据权限
+ * @return /
+ */
+ public static List getCurrentUserDataScope(){
+ UserDetails userDetails = getCurrentUser();
+ JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes"));
+ return JSONUtil.toList(array,Long.class);
+ }
+
+ /**
+ * 获取数据权限级别
+ * @return 级别
+ */
+ public static String getDataScopeType() {
+ List dataScopes = getCurrentUserDataScope();
+ if(dataScopes.size() != 0){
+ return "";
+ }
+ return DataScopeEnum.ALL.getValue();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SpringContextHolder.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SpringContextHolder.java
new file mode 100644
index 0000000..454b7c8
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SpringContextHolder.java
@@ -0,0 +1,145 @@
+/*
+ * 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 com.example.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 java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Jie
+ * 2019-01-07
+ */
+@Slf4j
+public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
+
+ private static ApplicationContext applicationContext = null;
+ private static final List CALL_BACKS = new ArrayList<>();
+ private static boolean addCallback = true;
+
+ /**
+ * 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。
+ * 在SpringContextHolder 初始化后,进行回调使用
+ *
+ * @param callBack 回调函数
+ */
+ public synchronized static void addCallBacks(CallBack callBack) {
+ if (addCallback) {
+ SpringContextHolder.CALL_BACKS.add(callBack);
+ } else {
+ log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName());
+ callBack.executor();
+ }
+ }
+
+ /**
+ * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+ */
+ @SuppressWarnings("unchecked")
+ public static T getBean(String name) {
+ assertContextInjected();
+ return (T) applicationContext.getBean(name);
+ }
+
+ /**
+ * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+ */
+ public static T getBean(Class requiredType) {
+ assertContextInjected();
+ return applicationContext.getBean(requiredType);
+ }
+
+ /**
+ * 获取SpringBoot 配置信息
+ *
+ * @param property 属性key
+ * @param defaultValue 默认值
+ * @param requiredType 返回类型
+ * @return /
+ */
+ public static T getProperties(String property, T defaultValue, Class 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 getProperties(String property, Class requiredType) {
+ return getProperties(property, null, requiredType);
+ }
+
+ /**
+ * 检查ApplicationContext不为空.
+ */
+ private static void assertContextInjected() {
+ if (applicationContext == null) {
+ throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
+ ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
+ }
+ }
+
+ /**
+ * 清除SpringContextHolder中的ApplicationContext为Null.
+ */
+ private static void clearHolder() {
+ log.debug("清除SpringContextHolder中的ApplicationContext:"
+ + applicationContext);
+ applicationContext = null;
+ }
+
+ @Override
+ public void destroy() {
+ SpringContextHolder.clearHolder();
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if (SpringContextHolder.applicationContext != null) {
+ log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
+ }
+ SpringContextHolder.applicationContext = applicationContext;
+ if (addCallback) {
+ for (CallBack callBack : SpringContextHolder.CALL_BACKS) {
+ callBack.executor();
+ }
+ CALL_BACKS.clear();
+ }
+ SpringContextHolder.addCallback = false;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/StringUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/StringUtils.java
new file mode 100644
index 0000000..a5fd454
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/StringUtils.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.utils;
+
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+import com.example.config.ElAdminProperties;
+import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
+import net.dreamlu.mica.ip2region.core.IpInfo;
+import nl.basjes.parse.useragent.UserAgent;
+import nl.basjes.parse.useragent.UserAgentAnalyzer;
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+
+/**
+ *
+ * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
+ */
+@Slf4j
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+
+ private static final char SEPARATOR = '_';
+ private static final String UNKNOWN = "unknown";
+
+ /**
+ * 注入bean
+ */
+ private final static Ip2regionSearcher IP_SEARCHER = SpringContextHolder.getBean(Ip2regionSearcher.class);
+
+
+ private static final UserAgentAnalyzer USER_AGENT_ANALYZER = UserAgentAnalyzer
+ .newBuilder()
+ .hideMatcherLoadStats()
+ .withCache(10000)
+ .withField(UserAgent.AGENT_NAME_VERSION)
+ .build();
+
+ /**
+ * 驼峰命名法工具
+ *
+ * @return toCamelCase(" hello_world ") == "helloWorld"
+ * toCapitalizeCamelCase("hello_world") == "HelloWorld"
+ * toUnderScoreCase("helloWorld") = "hello_world"
+ */
+ public static String toCamelCase(String s) {
+ if (s == null) {
+ return null;
+ }
+
+ s = s.toLowerCase();
+
+ StringBuilder sb = new StringBuilder(s.length());
+ boolean upperCase = false;
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+
+ if (c == SEPARATOR) {
+ upperCase = true;
+ } else if (upperCase) {
+ sb.append(Character.toUpperCase(c));
+ upperCase = false;
+ } else {
+ sb.append(c);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * 驼峰命名法工具
+ *
+ * @return toCamelCase(" hello_world ") == "helloWorld"
+ * toCapitalizeCamelCase("hello_world") == "HelloWorld"
+ * toUnderScoreCase("helloWorld") = "hello_world"
+ */
+ public static String toCapitalizeCamelCase(String s) {
+ if (s == null) {
+ return null;
+ }
+ s = toCamelCase(s);
+ return s.substring(0, 1).toUpperCase() + s.substring(1);
+ }
+
+ /**
+ * 驼峰命名法工具
+ *
+ * @return toCamelCase(" hello_world ") == "helloWorld"
+ * toCapitalizeCamelCase("hello_world") == "HelloWorld"
+ * toUnderScoreCase("helloWorld") = "hello_world"
+ */
+ static String toUnderScoreCase(String s) {
+ if (s == null) {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ boolean upperCase = false;
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+
+ boolean nextUpperCase = true;
+
+ if (i < (s.length() - 1)) {
+ nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
+ }
+
+ if ((i > 0) && Character.isUpperCase(c)) {
+ if (!upperCase || !nextUpperCase) {
+ sb.append(SEPARATOR);
+ }
+ upperCase = true;
+ } else {
+ upperCase = false;
+ }
+
+ sb.append(Character.toLowerCase(c));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * 获取ip地址
+ */
+ public static String getIp(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ String comma = ",";
+ String localhost = "127.0.0.1";
+ if (ip.contains(comma)) {
+ ip = ip.split(",")[0];
+ }
+ if (localhost.equals(ip)) {
+ // 获取本机真正的ip地址
+ try {
+ ip = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ return ip;
+ }
+
+ /**
+ * 根据ip获取详细地址
+ */
+ public static String getCityInfo(String ip) {
+ if (ElAdminProperties.ipLocal) {
+ return getLocalCityInfo(ip);
+ } else {
+ return getHttpCityInfo(ip);
+ }
+ }
+
+ /**
+ * 根据ip获取详细地址
+ */
+ public static String getHttpCityInfo(String ip) {
+ String api = String.format(ElAdminConstant.Url.IP_URL, ip);
+ JSONObject object = JSONUtil.parseObj(HttpUtil.get(api));
+ return object.get("addr", String.class);
+ }
+
+ /**
+ * 根据ip获取详细地址
+ */
+ public static String getLocalCityInfo(String ip) {
+ IpInfo ipInfo = IP_SEARCHER.memorySearch(ip);
+ if(ipInfo != null){
+ return ipInfo.getAddress();
+ }
+ return null;
+
+ }
+
+ public static String getBrowser(HttpServletRequest request) {
+ UserAgent.ImmutableUserAgent userAgent = USER_AGENT_ANALYZER.parse(request.getHeader("User-Agent"));
+ return userAgent.get(UserAgent.AGENT_NAME_VERSION).getValue();
+ }
+
+ /**
+ * 获得当天是周几
+ */
+ public static String getWeekDay() {
+ String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(new Date());
+
+ int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
+ if (w < 0) {
+ w = 0;
+ }
+ return weekDays[w];
+ }
+
+ /**
+ * 获取当前机器的IP
+ *
+ * @return /
+ */
+ public static String getLocalIp() {
+ try {
+ InetAddress candidateAddress = null;
+ // 遍历所有的网络接口
+ for (Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) {
+ NetworkInterface anInterface = interfaces.nextElement();
+ // 在所有的接口下再遍历IP
+ for (Enumeration 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 "";
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ThrowableUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ThrowableUtil.java
new file mode 100644
index 0000000..0ea7da7
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ThrowableUtil.java
@@ -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 com.example.utils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 异常工具 2019-01-06
+ *
+ */
+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();
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/TranslatorUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/TranslatorUtil.java
new file mode 100644
index 0000000..7d7087d
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/TranslatorUtil.java
@@ -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 com.example.utils;
+
+import cn.hutool.json.JSONArray;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+
+/**
+ *
+ * 翻译工具类
+ */
+public class TranslatorUtil {
+
+ public static String translate(String word){
+ try {
+ String url = "https://translate.googleapis.com/translate_a/single?" +
+ "client=gtx&" +
+ "sl=en" +
+ "&tl=zh-CN" +
+ "&dt=t&q=" + URLEncoder.encode(word, "UTF-8");
+
+ URL obj = new URL(url);
+ HttpURLConnection con = (HttpURLConnection) obj.openConnection();
+ con.setRequestProperty("User-Agent", "Mozilla/5.0");
+
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(con.getInputStream()));
+ String inputLine;
+ StringBuilder response = new StringBuilder();
+
+ while ((inputLine = in.readLine()) != null) {
+ response.append(inputLine);
+ }
+ in.close();
+ return parseResult(response.toString());
+ }catch (Exception e){
+ return word;
+ }
+ }
+
+ private static String parseResult(String inputJson){
+ JSONArray jsonArray2 = (JSONArray) new JSONArray(inputJson).get(0);
+ StringBuilder result = new StringBuilder();
+ for (Object o : jsonArray2) {
+ result.append(((JSONArray) o).get(0).toString());
+ }
+ return result.toString();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ValidationUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ValidationUtil.java
new file mode 100644
index 0000000..689ec6f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ValidationUtil.java
@@ -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 com.example.utils;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.example.exception.BadRequestException;
+import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator;
+
+/**
+ * 验证工具
+ *
+ * 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 new EmailValidator().isValid(email, null);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeBiEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeBiEnum.java
new file mode 100644
index 0000000..4f0147e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeBiEnum.java
@@ -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 com.example.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * 验证码业务场景
+ *
+ *
+ * 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;
+ }
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeEnum.java
new file mode 100644
index 0000000..17a1b2d
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeEnum.java
@@ -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 com.example.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * 验证码业务场景对应的 Redis 中的 key
+ *
+ *
+ * 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;
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/DataScopeEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/DataScopeEnum.java
new file mode 100644
index 0000000..18330f2
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/DataScopeEnum.java
@@ -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 com.example.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * 数据权限枚举
+ *
+ *
+ * 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;
+ }
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/RequestMethodEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/RequestMethodEnum.java
new file mode 100644
index 0000000..2edd703
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/RequestMethodEnum.java
@@ -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 com.example.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * @website https://el-admin.vip
+ * @description
+ * 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;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/PageUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/PageUtils.java
new file mode 100644
index 0000000..7f02b02
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/PageUtils.java
@@ -0,0 +1,145 @@
+/**
+
+ *
+
+ *
+ *
+ */
+
+package com.example.utils.page;
+
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 分页工具类
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class PageUtils implements Serializable {
+ private static final long serialVersionUID = 1L;
+ /**
+ * 总记录数
+ */
+ private int total;
+ /**
+ * 每页记录数
+ */
+ private int size;
+ /**
+ * 总页数
+ */
+ private int pages;
+ /**
+ * 当前页数
+ */
+ private int page;
+ /**
+ * 列表数据
+ */
+ private List> list;
+
+ private double totalTime;
+
+ private Object independentIpNum;
+
+ private int resultTotal;
+
+ public int getResultTotal() {
+ return resultTotal;
+ }
+
+ public void setResultTotal(int resultTotal) {
+ this.resultTotal = resultTotal;
+ }
+
+ /**
+ * 分页
+ * @param list 列表数据
+ * @param total 总记录数
+ * @param size 每页记录数
+ * @param page 当前页数
+ */
+ public PageUtils(List> list, int total, int size, int page ,double totalTime,int independentIpNum ,int resultTotal) {
+ this.list = list;
+ this.total = total;
+ this.size = size;
+ this.page = page;
+ this.totalTime = totalTime;
+ this.independentIpNum = independentIpNum;
+ this.resultTotal = resultTotal;
+ this.pages = (int)Math.ceil((double)total/size);
+ }
+
+ /**
+ * 分页
+ */
+ public PageUtils(IPage> page) {
+ this.list = page.getRecords();
+ this.total = (int)page.getTotal();
+ this.size = (int)page.getSize();
+ this.page = (int)page.getCurrent();
+ this.pages = (int)page.getPages();
+ }
+
+
+ public Object getIndependentIpNum() {
+ return independentIpNum;
+ }
+
+ public void setIndependentIpNum(Object independentIpNum) {
+ this.independentIpNum = independentIpNum;
+ }
+
+ public int getTotal() {
+ return total;
+ }
+
+ public void setTotal(int total) {
+ this.total = total;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ public int getPages() {
+ return pages;
+ }
+
+ public void setPages(int pages) {
+ this.pages = pages;
+ }
+
+ public int getPage() {
+ return page;
+ }
+
+ public double getTotalTime() {
+ return totalTime;
+ }
+
+ public void setTotalTime(double totalTime) {
+ this.totalTime = totalTime;
+ }
+
+ public void setPage(int page) {
+ this.page = page;
+ }
+
+ public List> getList() {
+ return list;
+ }
+
+ public void setList(List> list) {
+ this.list = list;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/Query.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/Query.java
new file mode 100644
index 0000000..765f2f6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/Query.java
@@ -0,0 +1,64 @@
+package com.example.utils.page;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import java.util.Map;
+
+/**
+ * 查询参数
+ */
+public class Query {
+
+ private Class clz;
+
+ public Class extends Object> getClz() {
+ return clz;
+ }
+
+ public void setClz(Class clz) {
+ this.clz = clz;
+ }
+
+ public Query(Class clz) {
+ this.clz = clz;
+ }
+
+ public IPage getPage(Map params) {
+ return this.getPage(params, null, false);
+ }
+
+ public IPage getPage(Map params, String defaultOrderField, boolean isAsc) {
+ //分页参数
+ long curPage = 1;
+ long limit = 10;
+
+ if(params.get("page") != null && !"".equals(params.get("page"))){
+ curPage = Long.parseLong((String)params.get("page"));
+ }
+ if(params.get("size") != null && !"".equals(params.get("size"))){
+ limit = Long.parseLong((String)params.get("size"));
+ if(limit == -1){
+ limit = Long.MAX_VALUE;
+ curPage = 0;
+ }
+ }
+
+ //分页对象
+ Page page = new Page(curPage, limit);
+
+ //分页参数
+ params.put("page", page);
+
+
+ // 默认排序
+ if(isAsc) {
+ page.setAsc(defaultOrderField);
+ }else {
+ page.setDesc(defaultOrderField);
+ }
+
+ return page;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/R.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/R.java
new file mode 100644
index 0000000..92db65a
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/R.java
@@ -0,0 +1,40 @@
+package com.example.utils.page;
+
+import cn.hutool.core.date.DateUtil;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class R extends HashMap {
+ private static final long serialVersionUID = 1L;
+
+ public R() {
+ put("status", 200);
+ put("message", "success");
+ put("timestamp", new Date());
+ }
+
+ public static R ok(String message) {
+ R r = new R();
+ r.put("message", message);
+ r.put("timestamp", new Date());
+ return r;
+ }
+
+ public static R ok() {
+ return new R();
+ }
+
+ public static R ok(Object data) {
+ R r = new R();
+ r.put("data", data);
+ r.put("timestamp", new Date());
+ return r;
+ }
+
+
+}
+
+
diff --git a/UI source code/dns-dev-2.0/dns-logging/pom.xml b/UI source code/dns-dev-2.0/dns-logging/pom.xml
new file mode 100644
index 0000000..f3c2cc9
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ dns
+ com.example
+ 2.6
+
+ 4.0.0
+
+ dns-logging
+ dns-logging
+
+
+
+ com.example
+ dns-common
+ 2.6
+
+
+
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/annotation/Log.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/annotation/Log.java
new file mode 100644
index 0000000..566b555
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/annotation/Log.java
@@ -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 com.example.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * 2018-11-24
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Log {
+ String value() default "";
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/aspect/LogAspect.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/aspect/LogAspect.java
new file mode 100644
index 0000000..aaed973
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/aspect/LogAspect.java
@@ -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 com.example.aspect;
+
+import com.example.utils.RequestHolder;
+import com.example.utils.SecurityUtils;
+import com.example.utils.StringUtils;
+import com.example.utils.ThrowableUtil;
+import lombok.extern.slf4j.Slf4j;
+import com.example.domain.Log;
+import com.example.service.LogService;
+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;
+
+/**
+ *
+ * 2018-11-24
+ */
+@Component
+@Aspect
+@Slf4j
+public class LogAspect {
+
+ private final LogService logService;
+
+ ThreadLocal currentTime = new ThreadLocal<>();
+
+ public LogAspect(LogService logService) {
+ this.logService = logService;
+ }
+
+ /**
+ * 配置切入点
+ */
+ @Pointcut("@annotation(com.example.annotation.Log)")
+ public void logPointcut() {
+ // 该方法无方法体,主要为了让同类中其他方法使用此切入点
+ }
+
+ /**
+ * 配置环绕通知,使用在方法logPointcut()上注册的切入点
+ *
+ * @param joinPoint join point for advice
+ */
+ @Around("logPointcut()")
+ public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
+ Object result;
+ currentTime.set(System.currentTimeMillis());
+ result = joinPoint.proceed();
+ Log log = new Log("INFO",System.currentTimeMillis() - currentTime.get());
+ currentTime.remove();
+ HttpServletRequest request = RequestHolder.getHttpServletRequest();
+ logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log);
+ return result;
+ }
+
+ /**
+ * 配置异常通知
+ *
+ * @param joinPoint join point for advice
+ * @param e exception
+ */
+ @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
+ public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
+ Log log = new Log("ERROR",System.currentTimeMillis() - currentTime.get());
+ currentTime.remove();
+ log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
+ HttpServletRequest request = RequestHolder.getHttpServletRequest();
+ logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log);
+ }
+
+ public String getUsername() {
+ try {
+ return SecurityUtils.getCurrentUsername();
+ }catch (Exception e){
+ return "";
+ }
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/domain/Log.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/domain/Log.java
new file mode 100644
index 0000000..21529a6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/domain/Log.java
@@ -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 com.example.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;
+
+/**
+ *
+ * 2018-11-24
+ */
+@Entity
+@Getter
+@Setter
+@Table(name = "sys_log")
+@NoArgsConstructor
+public class Log implements Serializable {
+
+ @Id
+ @Column(name = "log_id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ /** 操作用户 */
+ private String username;
+
+ /** 描述 */
+ private String description;
+
+ /** 方法名 */
+ private String method;
+
+ /** 参数 */
+ private String params;
+
+ /** 日志类型 */
+ private String logType;
+
+ /** 请求ip */
+ private String requestIp;
+
+ /** 地址 */
+ private String address;
+
+ /** 浏览器 */
+ private String browser;
+
+ /** 请求耗时 */
+ private Long time;
+
+ /** 异常详细 */
+ private byte[] exceptionDetail;
+
+ /** 创建日期 */
+ @CreationTimestamp
+ private Timestamp createTime;
+
+ public Log(String logType, Long time) {
+ this.logType = logType;
+ this.time = time;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/repository/LogRepository.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/repository/LogRepository.java
new file mode 100644
index 0000000..d689cfe
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/repository/LogRepository.java
@@ -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 com.example.repository;
+
+import com.example.domain.Log;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * 2018-11-24
+ */
+@Repository
+public interface LogRepository extends JpaRepository, JpaSpecificationExecutor {
+
+ /**
+ * 根据日志类型删除信息
+ * @param logType 日志类型
+ */
+ @Modifying
+ @Query(value = "delete from sys_log where log_type = ?1", nativeQuery = true)
+ void deleteByLogType(String logType);
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/rest/LogController.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/rest/LogController.java
new file mode 100644
index 0000000..305f2bb
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/rest/LogController.java
@@ -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 com.example.rest;
+
+import com.example.utils.SecurityUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import com.example.annotation.Log;
+import com.example.service.LogService;
+import com.example.service.dto.LogQueryCriteria;
+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;
+
+/**
+ *
+ * 2018-11-24
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/logs")
+@Api(tags = "系统:日志管理")
+public class LogController {
+
+ private final LogService logService;
+
+ @Log("导出数据")
+ @ApiOperation("导出数据")
+ @GetMapping(value = "/download")
+ @PreAuthorize("@el.check()")
+ public void exportLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException {
+ criteria.setLogType("INFO");
+ logService.download(logService.queryAll(criteria), response);
+ }
+
+ @Log("导出错误数据")
+ @ApiOperation("导出错误数据")
+ @GetMapping(value = "/error/download")
+ @PreAuthorize("@el.check()")
+ public void exportErrorLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException {
+ criteria.setLogType("ERROR");
+ logService.download(logService.queryAll(criteria), response);
+ }
+ @GetMapping
+ @ApiOperation("日志查询")
+ @PreAuthorize("@el.check()")
+ public ResponseEntity queryLog(LogQueryCriteria criteria, Pageable pageable){
+ criteria.setLogType("INFO");
+ return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK);
+ }
+
+ @GetMapping(value = "/user")
+ @ApiOperation("用户日志查询")
+ public ResponseEntity queryUserLog(LogQueryCriteria criteria, Pageable pageable){
+ criteria.setLogType("INFO");
+ criteria.setBlurry(SecurityUtils.getCurrentUsername());
+ return new ResponseEntity<>(logService.queryAllByUser(criteria,pageable), HttpStatus.OK);
+ }
+
+ @GetMapping(value = "/error")
+ @ApiOperation("错误日志查询")
+ @PreAuthorize("@el.check()")
+ public ResponseEntity queryErrorLog(LogQueryCriteria criteria, Pageable pageable){
+ criteria.setLogType("ERROR");
+ return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK);
+ }
+
+ @GetMapping(value = "/error/{id}")
+ @ApiOperation("日志异常详情查询")
+ @PreAuthorize("@el.check()")
+ public ResponseEntity queryErrorLogDetail(@PathVariable Long id){
+ return new ResponseEntity<>(logService.findByErrDetail(id), HttpStatus.OK);
+ }
+ @DeleteMapping(value = "/del/error")
+ @Log("删除所有ERROR日志")
+ @ApiOperation("删除所有ERROR日志")
+ @PreAuthorize("@el.check()")
+ public ResponseEntity delAllErrorLog(){
+ logService.delAllByError();
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+
+ @DeleteMapping(value = "/del/info")
+ @Log("删除所有INFO日志")
+ @ApiOperation("删除所有INFO日志")
+ @PreAuthorize("@el.check()")
+ public ResponseEntity delAllInfoLog(){
+ logService.delAllByInfo();
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/LogService.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/LogService.java
new file mode 100644
index 0000000..b640559
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/LogService.java
@@ -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 com.example.service;
+
+import com.example.domain.Log;
+import com.example.service.dto.LogQueryCriteria;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.springframework.data.domain.Pageable;
+import org.springframework.scheduling.annotation.Async;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ *
+ * 2018-11-24
+ */
+public interface LogService {
+
+ /**
+ * 分页查询
+ * @param criteria 查询条件
+ * @param pageable 分页参数
+ * @return /
+ */
+ Object queryAll(LogQueryCriteria criteria, Pageable pageable);
+
+ /**
+ * 查询全部数据
+ * @param criteria 查询条件
+ * @return /
+ */
+ List queryAll(LogQueryCriteria criteria);
+
+ /**
+ * 查询用户日志
+ * @param criteria 查询条件
+ * @param pageable 分页参数
+ * @return -
+ */
+ Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable);
+
+ /**
+ * 保存日志数据
+ * @param username 用户
+ * @param browser 浏览器
+ * @param ip 请求IP
+ * @param joinPoint /
+ * @param log 日志实体
+ */
+ @Async
+ void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log);
+
+ /**
+ * 查询异常详情
+ * @param id 日志ID
+ * @return Object
+ */
+ Object findByErrDetail(Long id);
+
+ /**
+ * 导出日志
+ * @param logs 待导出的数据
+ * @param response /
+ * @throws IOException /
+ */
+ void download(List logs, HttpServletResponse response) throws IOException;
+
+ /**
+ * 删除所有错误日志
+ */
+ void delAllByError();
+
+ /**
+ * 删除所有INFO日志
+ */
+ void delAllByInfo();
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogErrorDTO.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogErrorDTO.java
new file mode 100644
index 0000000..734bda3
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogErrorDTO.java
@@ -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 com.example.service.dto;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+/**
+*
+* 2019-5-22
+*/
+@Data
+public class LogErrorDTO implements Serializable {
+
+ private Long id;
+
+ private String username;
+
+ private String description;
+
+ private String method;
+
+ private String params;
+
+ private String browser;
+
+ private String requestIp;
+
+ private String address;
+
+ private Timestamp createTime;
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogQueryCriteria.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogQueryCriteria.java
new file mode 100644
index 0000000..9611dfb
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogQueryCriteria.java
@@ -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 com.example.service.dto;
+
+import lombok.Data;
+import com.example.annotation.Query;
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ * 日志查询类
+ *
+ * 2019-6-4 09:23:07
+ */
+@Data
+public class LogQueryCriteria {
+
+ @Query(blurry = "username,description,address,requestIp,method,params")
+ private String blurry;
+
+ @Query
+ private String logType;
+
+ @Query(type = Query.Type.BETWEEN)
+ private List createTime;
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogSmallDTO.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogSmallDTO.java
new file mode 100644
index 0000000..d78f9d9
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogSmallDTO.java
@@ -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 com.example.service.dto;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+/**
+ *
+ * 2019-5-22
+ */
+@Data
+public class LogSmallDTO implements Serializable {
+
+ private String description;
+
+ private String requestIp;
+
+ private Long time;
+
+ private String address;
+
+ private String browser;
+
+ private Timestamp createTime;
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/impl/LogServiceImpl.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/impl/LogServiceImpl.java
new file mode 100644
index 0000000..43b94b8
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/impl/LogServiceImpl.java
@@ -0,0 +1,169 @@
+/*
+ * 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 com.example.service.impl;
+
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.example.domain.Log;
+import com.example.service.LogService;
+import com.example.service.dto.LogQueryCriteria;
+import com.example.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.example.repository.LogRepository;
+import com.example.service.mapstruct.LogErrorMapper;
+import com.example.service.mapstruct.LogSmallMapper;
+import com.example.utils.*;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.*;
+
+/**
+ *
+ * 2018-11-24
+ */
+@Service
+@RequiredArgsConstructor
+public class LogServiceImpl implements LogService {
+ private final LogRepository logRepository;
+ private final LogErrorMapper logErrorMapper;
+ private final LogSmallMapper logSmallMapper;
+
+ @Override
+ public Object queryAll(LogQueryCriteria criteria, Pageable pageable) {
+ Page page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable);
+ String status = "ERROR";
+ if (status.equals(criteria.getLogType())) {
+ return PageUtil.toPage(page.map(logErrorMapper::toDto));
+ }
+ return page;
+ }
+
+ @Override
+ public List queryAll(LogQueryCriteria criteria) {
+ return logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)));
+ }
+
+ @Override
+ public Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable) {
+ Page page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable);
+ return PageUtil.toPage(page.map(logSmallMapper::toDto));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log) {
+ if (log == null) {
+ throw new IllegalArgumentException("Log 不能为 null!");
+ }
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+ Method method = signature.getMethod();
+ com.example.annotation.Log aopLog = method.getAnnotation(com.example.annotation.Log.class);
+
+ // 方法路径
+ String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
+
+ // 描述
+ log.setDescription(aopLog.value());
+
+ log.setRequestIp(ip);
+ log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
+ log.setMethod(methodName);
+ log.setUsername(username);
+ log.setParams(getParameter(method, joinPoint.getArgs()));
+ log.setBrowser(browser);
+ logRepository.save(log);
+ }
+
+ /**
+ * 根据方法和传入的参数获取请求参数
+ */
+ private String getParameter(Method method, Object[] args) {
+ List argList = new ArrayList<>();
+ Parameter[] parameters = method.getParameters();
+ for (int i = 0; i < parameters.length; i++) {
+ //将RequestBody注解修饰的参数作为请求参数
+ RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
+ if (requestBody != null) {
+ argList.add(args[i]);
+ }
+ //将RequestParam注解修饰的参数作为请求参数
+ RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
+ if (requestParam != null) {
+ Map map = new HashMap<>(4);
+ String key = parameters[i].getName();
+ if (!StringUtils.isEmpty(requestParam.value())) {
+ key = requestParam.value();
+ }
+ map.put(key, args[i]);
+ argList.add(map);
+ }
+ }
+ if (argList.isEmpty()) {
+ return "";
+ }
+ return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : JSONUtil.toJsonStr(argList);
+ }
+
+ @Override
+ public Object findByErrDetail(Long id) {
+ Log log = logRepository.findById(id).orElseGet(Log::new);
+ ValidationUtil.isNull(log.getId(), "Log", "id", id);
+ byte[] details = log.getExceptionDetail();
+ return Dict.create().set("exception", new String(ObjectUtil.isNotNull(details) ? details : "".getBytes()));
+ }
+
+ @Override
+ public void download(List logs, HttpServletResponse response) throws IOException {
+ List> list = new ArrayList<>();
+ for (Log log : logs) {
+ Map map = new LinkedHashMap<>();
+ map.put("用户名", log.getUsername());
+ map.put("IP", log.getRequestIp());
+ map.put("IP来源", log.getAddress());
+ map.put("描述", log.getDescription());
+ map.put("浏览器", log.getBrowser());
+ map.put("请求耗时/毫秒", log.getTime());
+ map.put("异常详情", new String(ObjectUtil.isNotNull(log.getExceptionDetail()) ? log.getExceptionDetail() : "".getBytes()));
+ map.put("创建日期", log.getCreateTime());
+ list.add(map);
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delAllByError() {
+ logRepository.deleteByLogType("ERROR");
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void delAllByInfo() {
+ logRepository.deleteByLogType("INFO");
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogErrorMapper.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogErrorMapper.java
new file mode 100644
index 0000000..8a19a28
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogErrorMapper.java
@@ -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 com.example.service.mapstruct;
+
+import com.example.base.BaseMapper;
+import com.example.domain.Log;
+import com.example.service.dto.LogErrorDTO;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ *
+ * 2019-5-22
+ */
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface LogErrorMapper extends BaseMapper {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogSmallMapper.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogSmallMapper.java
new file mode 100644
index 0000000..8c06ba4
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogSmallMapper.java
@@ -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 com.example.service.mapstruct;
+
+import com.example.base.BaseMapper;
+import com.example.domain.Log;
+import com.example.service.dto.LogSmallDTO;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ *
+ * 2019-5-22
+ */
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface LogSmallMapper extends BaseMapper {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/pom.xml b/UI source code/dns-dev-2.0/dns-system/pom.xml
new file mode 100644
index 0000000..ea50602
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/pom.xml
@@ -0,0 +1,103 @@
+
+
+
+ dns
+ com.example
+ 2.6
+
+ 4.0.0
+
+ dns-system
+ dns-system
+
+
+ 0.11.1
+
+ 5.8.0
+
+
+
+
+
+
+
+ com.example
+ dns-common
+ 2.6
+
+
+ com.example
+ dns-logging
+ 2.6
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jjwt.version}
+
+
+
+
+ org.quartz-scheduler
+ quartz
+
+
+
+
+ ch.ethz.ganymed
+ ganymed-ssh2
+ build210
+
+
+ com.jcraft
+ jsch
+ 0.1.55
+
+
+
+
+ com.github.oshi
+ oshi-core
+ 5.7.1
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java
new file mode 100644
index 0000000..521f939
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example;
+
+import com.example.utils.SpringContextHolder;
+import io.swagger.annotations.Api;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 开启审计功能 -> @EnableJpaAuditing
+ *
+ * 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/dns/app.pid
+ // 或者在 application.yml 添加文件路径,方便 kill,kill `cat /home/dns/app.pid`
+ springApplication.addListeners(new ApplicationPidFileWriter());
+ springApplication.run(args);
+ }
+
+ @Bean
+ public SpringContextHolder springContextHolder() {
+ return new SpringContextHolder();
+ }
+
+ @Bean
+ public ServletWebServerFactory webServerFactory() {
+ TomcatServletWebServerFactory fa = new TomcatServletWebServerFactory();
+ fa.addConnectorCustomizers(connector -> connector.setProperty("relaxedQueryChars", "[]{}"));
+ return fa;
+ }
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java
new file mode 100644
index 0000000..b2bcf86
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java
@@ -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 com.example.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
+ *
+ *
+ * 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.addAllowedOrigin("*");
+ 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> converters) {
+ // 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换
+ FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
+ List 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);
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..87e8cbf
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java
@@ -0,0 +1,236 @@
+package com.example.config;
+
+import cn.hutool.log.Log;
+import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
+import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
+import com.baomidou.mybatisplus.core.MybatisConfiguration;
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
+import com.baomidou.mybatisplus.core.injector.ISqlInjector;
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.mapping.DatabaseIdProvider;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.mybatis.spring.mapper.ClassPathMapperScanner;
+import org.mybatis.spring.mapper.MapperFactoryBean;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.context.annotation.*;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.PostConstruct;
+import javax.sql.DataSource;
+import java.util.List;
+
+/**
+ * mybatis-plus 初始化配置
+ */
+@Configuration
+@EnableConfigurationProperties(MybatisPlusProperties.class)
+public class MybatisPlusConfig {
+
+ public MybatisPlusConfig(MybatisPlusProperties properties, ObjectProvider interceptorsProvider,
+ ResourceLoader resourceLoader, ObjectProvider databaseIdProvider,
+ ObjectProvider> configurationCustomizersProvider,
+ ApplicationContext applicationContext) {
+ this.properties = properties;
+ this.interceptors = interceptorsProvider.getIfAvailable();
+ this.resourceLoader = resourceLoader;
+ this.databaseIdProvider = databaseIdProvider.getIfAvailable();
+ this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
+ this.applicationContext = applicationContext;
+ }
+
+ private static final Log logger = Log.get();
+
+ private final MybatisPlusProperties properties;
+
+ private final Interceptor[] interceptors;
+
+ private final ResourceLoader resourceLoader;
+
+ private final DatabaseIdProvider databaseIdProvider;
+
+ private final List configurationCustomizers;
+
+ private final ApplicationContext applicationContext;
+
+ @PostConstruct
+ public void checkConfigFileExists() {
+ if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
+ Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
+ Assert.state(resource.exists(), "Cannot find config location: " + resource
+ + " (please add config file or check your Mybatis configuration)");
+ }
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
+ MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
+ factory.setDataSource(dataSource);
+ factory.setVfs(SpringBootVFS.class);
+ if (StringUtils.hasText(this.properties.getConfigLocation())) {
+ factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
+ }
+ applyConfiguration(factory);
+ if (this.properties.getConfigurationProperties() != null) {
+ factory.setConfigurationProperties(this.properties.getConfigurationProperties());
+ }
+ if (!ObjectUtils.isEmpty(this.interceptors)) {
+ factory.setPlugins(this.interceptors);
+ }
+ if (this.databaseIdProvider != null) {
+ factory.setDatabaseIdProvider(this.databaseIdProvider);
+ }
+ if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
+ factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
+ }
+ // TODO 自定义枚举包
+ if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) {
+ factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage());
+ }
+ if (this.properties.getTypeAliasesSuperType() != null) {
+ factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
+ }
+ if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
+ factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
+ }
+ if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
+ factory.setMapperLocations(this.properties.resolveMapperLocations());
+ }
+ // TODO 此处必为非 NULL
+ GlobalConfig globalConfig = this.properties.getGlobalConfig();
+ // 注入填充器
+ if (this.applicationContext.getBeanNamesForType(MetaObjectHandler.class, false, false).length > 0) {
+ MetaObjectHandler metaObjectHandler = this.applicationContext.getBean(MetaObjectHandler.class);
+ globalConfig.setMetaObjectHandler(metaObjectHandler);
+ }
+ // 注入主键生成器
+ if (this.applicationContext.getBeanNamesForType(IKeyGenerator.class, false, false).length > 0) {
+ IKeyGenerator keyGenerator = this.applicationContext.getBean(IKeyGenerator.class);
+ globalConfig.getDbConfig().setKeyGenerator(keyGenerator);
+ }
+ // 注入sql注入器
+ if (this.applicationContext.getBeanNamesForType(ISqlInjector.class, false, false).length > 0) {
+ ISqlInjector iSqlInjector = this.applicationContext.getBean(ISqlInjector.class);
+ globalConfig.setSqlInjector(iSqlInjector);
+ }
+ factory.setGlobalConfig(globalConfig);
+ return factory.getObject();
+ }
+
+ private void applyConfiguration(MybatisSqlSessionFactoryBean factory) {
+ MybatisConfiguration configuration = this.properties.getConfiguration();
+ if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
+ configuration = new MybatisConfiguration();
+ }
+ if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
+ for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
+ customizer.customize(configuration);
+ }
+ }
+ factory.setConfiguration(configuration);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
+ ExecutorType executorType = this.properties.getExecutorType();
+ if (executorType != null) {
+ return new SqlSessionTemplate(sqlSessionFactory, executorType);
+ } else {
+ return new SqlSessionTemplate(sqlSessionFactory);
+ }
+ }
+
+ /**
+ * This will just scan the same base package as Spring Boot does. If you want
+ * more power, you can explicitly use
+ * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed
+ * mappers working correctly, out-of-the-box, similar to using Spring Data JPA
+ * repositories.
+ */
+ public static class AutoConfiguredMapperScannerRegistrar
+ implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
+
+ private BeanFactory beanFactory;
+
+ private ResourceLoader resourceLoader;
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ BeanDefinitionRegistry registry) {
+
+ logger.debug("Searching for mappers annotated with @Mapper");
+
+ ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
+
+ try {
+ if (this.resourceLoader != null) {
+ scanner.setResourceLoader(this.resourceLoader);
+ }
+
+ List packages = AutoConfigurationPackages.get(this.beanFactory);
+ if (logger.isDebugEnabled()) {
+ packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));
+ }
+
+ scanner.setAnnotationClass(Mapper.class);
+ scanner.registerFilters();
+ scanner.doScan(StringUtils.toStringArray(packages));
+ } catch (IllegalStateException ex) {
+ logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
+ }
+ }
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public void setResourceLoader(ResourceLoader resourceLoader) {
+ this.resourceLoader = resourceLoader;
+ }
+ }
+
+ /**
+ * {@link org.mybatis.spring.annotation.MapperScan} ultimately ends up creating
+ * instances of {@link MapperFactoryBean}. If
+ * {@link org.mybatis.spring.annotation.MapperScan} is used then this
+ * auto-configuration is not needed. If it is _not_ used, however, then this
+ * will bring in a bean registrar and automatically register components based on
+ * the same component-scanning path as Spring Boot itself.
+ */
+ @Configuration
+ @Import({ AutoConfiguredMapperScannerRegistrar.class })
+ @ConditionalOnMissingBean(MapperFactoryBean.class)
+ public static class MapperScannerRegistrarNotFoundConfiguration {
+
+ @PostConstruct
+ public void afterPropertiesSet() {
+ logger.debug("No {} found.", MapperFactoryBean.class.getName());
+ }
+ }
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java
new file mode 100644
index 0000000..cc9739c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java
@@ -0,0 +1,36 @@
+package com.example.config;
+
+import cn.hutool.log.Log;
+import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
+import com.baomidou.mybatisplus.core.injector.ISqlInjector;
+import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+/**
+ * mybatis-plus 插件配置
+ */
+@Configuration
+public class MybatisPlusPluginsConfig {
+
+ private static final Log logger = Log.get();
+
+ /**
+ * 分页插件
+ */
+ @Bean
+ public PaginationInterceptor paginationInterceptor() {
+ return new PaginationInterceptor();
+ }
+
+
+ @Bean
+ public ISqlInjector sqlInjector() {
+ return new LogicSqlInjector();
+ }
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java
new file mode 100644
index 0000000..906021c
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java
@@ -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 com.example.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+/**
+ * @author ZhangHouYing
+ * 2019-08-24 15:44
+ */
+@Configuration
+public class WebSocketConfig {
+
+ @Bean
+ public ServerEndpointExporter serverEndpointExporter() {
+ return new ServerEndpointExporter();
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java
new file mode 100644
index 0000000..44abd3d
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.config.thread;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 异步任务线程池装配类
+ * @author https://juejin.im/entry/5abb8f6951882555677e9da2
+ * 2019年10月31日15:06:18
+ */
+@Slf4j
+@Configuration
+public class AsyncTaskExecutePool implements AsyncConfigurer {
+
+ @Override
+ public Executor getAsyncExecutor() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ //核心线程池大小
+ executor.setCorePoolSize(AsyncTaskProperties.corePoolSize);
+ //最大线程数
+ executor.setMaxPoolSize(AsyncTaskProperties.maxPoolSize);
+ //队列容量
+ executor.setQueueCapacity(AsyncTaskProperties.queueCapacity);
+ //活跃时间
+ executor.setKeepAliveSeconds(AsyncTaskProperties.keepAliveSeconds);
+ //线程名字前缀
+ executor.setThreadNamePrefix("el-async-");
+ // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
+ // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+ executor.initialize();
+ return executor;
+ }
+
+ @Override
+ public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+ return (throwable, method, objects) -> {
+ log.error("===="+throwable.getMessage()+"====", throwable);
+ log.error("exception method:"+method.getName());
+ };
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java
new file mode 100644
index 0000000..012a127
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java
@@ -0,0 +1,58 @@
+/*
+ * 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 com.example.config.thread;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * 线程池配置属性类
+ * @author https://juejin.im/entry/5abb8f6951882555677e9da2
+ * 2019年10月31日14:58:18
+ */
+@Data
+@Component
+public class AsyncTaskProperties {
+
+ public static int corePoolSize;
+
+ public static int maxPoolSize;
+
+ public static int keepAliveSeconds;
+
+ public static int queueCapacity;
+
+ @Value("${task.pool.core-pool-size}")
+ public void setCorePoolSize(int corePoolSize) {
+ AsyncTaskProperties.corePoolSize = corePoolSize;
+ }
+
+ @Value("${task.pool.max-pool-size}")
+ public void setMaxPoolSize(int maxPoolSize) {
+ AsyncTaskProperties.maxPoolSize = maxPoolSize;
+ }
+
+ @Value("${task.pool.keep-alive-seconds}")
+ public void setKeepAliveSeconds(int keepAliveSeconds) {
+ AsyncTaskProperties.keepAliveSeconds = keepAliveSeconds;
+ }
+
+ @Value("${task.pool.queue-capacity}")
+ public void setQueueCapacity(int queueCapacity) {
+ AsyncTaskProperties.queueCapacity = queueCapacity;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java
new file mode 100644
index 0000000..b06a723
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java
@@ -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 com.example.config.thread;
+
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 自定义线程名称
+ *
+ * 2019年10月31日17:49:55
+ */
+@Component
+public class TheadFactoryName implements ThreadFactory {
+
+ private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
+ private final ThreadGroup group;
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+ private final String namePrefix;
+
+ public TheadFactoryName() {
+ this("el-pool");
+ }
+
+ private TheadFactoryName(String name){
+ SecurityManager s = System.getSecurityManager();
+ group = (s != null) ? s.getThreadGroup() :
+ Thread.currentThread().getThreadGroup();
+ //此时namePrefix就是 name + 第几个用这个工厂创建线程池的
+ this.namePrefix = name +
+ POOL_NUMBER.getAndIncrement();
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ //此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
+ Thread t = new Thread(group, r,
+ namePrefix + "-thread-"+threadNumber.getAndIncrement(),
+ 0);
+ if (t.isDaemon()) {
+ t.setDaemon(false);
+ }
+ if (t.getPriority() != Thread.NORM_PRIORITY) {
+ t.setPriority(Thread.NORM_PRIORITY);
+ }
+ return t;
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java
new file mode 100644
index 0000000..db542cf
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java
@@ -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 com.example.config.thread;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 用于获取自定义线程池
+ *
+ * 2019年10月31日18:16:47
+ */
+public class ThreadPoolExecutorUtil {
+
+ public static ThreadPoolExecutor getPoll(){
+ return new ThreadPoolExecutor(
+ AsyncTaskProperties.corePoolSize,
+ AsyncTaskProperties.maxPoolSize,
+ AsyncTaskProperties.keepAliveSeconds,
+ TimeUnit.SECONDS,
+ new ArrayBlockingQueue<>(AsyncTaskProperties.queueCapacity),
+ new TheadFactoryName()
+ );
+ }
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java
new file mode 100644
index 0000000..581a46b
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java
@@ -0,0 +1,48 @@
+package com.example.modules.dns.controller;
+
+import com.example.modules.dns.service.DnsService;
+import com.example.utils.page.PageUtils;
+import com.example.utils.page.R;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.text.DecimalFormat;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/dns")
+public class DnsController {
+ @Autowired
+ private DnsService dnsService;
+
+ @GetMapping
+ public R queryPage(@RequestParam Map params) {
+ long startTime = System.currentTimeMillis();
+ PageUtils page =dnsService.queryPage(params);
+ long endTime = System.currentTimeMillis();
+ DecimalFormat df = new DecimalFormat("0.000");
+ String totalTime = df.format((float) (endTime - startTime) / 1000);
+ page.setTotalTime(Double.parseDouble(totalTime));
+ return R.ok(page);
+ }
+
+
+ //区域数据统计
+ @GetMapping("/dataCount")
+ public R dataCount(@RequestParam Map params) {
+ return R.ok(dnsService.dataCount(params));
+ }
+
+ //区域数据统计
+ @GetMapping("/mapData")
+ public R mapData() {
+ return R.ok(dnsService.mapData());
+ }
+
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java
new file mode 100644
index 0000000..983c2ee
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java
@@ -0,0 +1,24 @@
+
+package com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.io.Serializable;
+
+
+@Data
+@TableName("dns_type")
+public class DnsType implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String ip;
+
+ private String type;
+
+ private int epoch;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java
new file mode 100644
index 0000000..5a772e2
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java
@@ -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 com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+@Data
+@TableName("doh_attribute")
+public class DohAttribute implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+ private String ip;
+ private Integer port;
+ private String host;
+ private String path;
+ private String method;
+ private Integer connectType;
+ private Integer statusCode;
+ private String repHeader;
+ private String repBody;
+ private Date timestamp;
+
+ private String component;
+
+ private int rounds;
+
+ @TableField(exist = false)
+ private List pathList;
+
+ @TableField(exist = false)
+ private List componentList;
+
+ @TableField(exist = false)
+ private List ipCert;
+
+ @TableField(exist = false)
+ private List ipInformation;
+
+ @TableField(exist = false)
+ private List> vulnerability;
+ @TableField(exist = false)
+ private List tags;
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java
new file mode 100644
index 0000000..5823a34
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java
@@ -0,0 +1,24 @@
+
+package com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.io.Serializable;
+
+
+@Data
+@TableName("forward_dns")
+public class ForwardDns implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String forwarder;
+
+ private String upstream;
+
+ private int epoch;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java
new file mode 100644
index 0000000..a7f88af
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java
@@ -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 com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.example.modules.system.domain.Dept;
+import com.example.modules.system.domain.Job;
+import com.example.modules.system.domain.Role;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * 2018-11-22
+ */
+@Data
+@TableName("ip_cert")
+public class IpCert implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String ip;
+
+ private String port;
+
+ private String certificate;
+
+ private String ca;
+
+ private Date timestamp;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java
new file mode 100644
index 0000000..1c61eb5
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ *
+ * 2018-11-22
+ */
+@Data
+@TableName("ip_information")
+public class IpInformation implements Serializable {
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String ip;
+
+ private String country;
+
+ private String province;
+
+ private String city;
+ private String district;
+ private String provider;
+ private String isp;
+ private Integer asnumber;
+ private Date timestamp;
+ private String zipcode;
+ private String timezone;
+
+ @TableField(exist = false)
+ private List ipCert;
+
+ @TableField(exist = false)
+ private List nonstandardDns;
+
+
+ @TableField(exist = false)
+ private DnsType dnsType;
+
+ @TableField(exist = false)
+ private List dohAttribute;
+
+ @TableField(exist = false)
+ private List forwardDns;
+
+ @TableField(exist = false)
+ private ScanResult scanResult;
+
+ @TableField(exist = false)
+ private Integer dnsTypeValue;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java
new file mode 100644
index 0000000..11badef
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java
@@ -0,0 +1,28 @@
+
+package com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.io.Serializable;
+
+
+/**
+ *
+ * 直接响DNS表
+ */
+@Data
+ @TableName("nonstandard_dns")
+public class NonstandardDns implements Serializable {
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String ip;
+
+ private String record;
+
+ private int epoch;
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java
new file mode 100644
index 0000000..6047df6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java
@@ -0,0 +1,71 @@
+package com.example.modules.dns.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class Result implements Serializable {
+
+ private Long id;
+ private String ip;
+
+ private String protocolType;
+ private String ipType;
+
+ private Integer port;
+ private String host;
+ private String path;
+ private String method;
+ private Integer connectType;
+ private Integer statusCode;
+ private String repHeader;
+ private String repBody;
+ private Date timestamp;
+ private String component;
+
+
+ private Integer flags;
+ private Integer opcode;
+ private Integer qr;
+ //权威标志位
+ private Integer aa;
+ //递归标志位
+ private Integer ra;
+ private Integer rcode;
+ private String queryName;
+ private String queryResponse;
+
+ //(预留)ipv4,ipv6,dnssec,tcp,udp等
+ private Integer scanType;
+
+ private Date time;
+
+ private Integer epoch;
+
+ private Integer rounds;
+
+
+ private Integer dnsType;
+
+ private String uuid;
+
+ private List pathList;
+
+ private List componentList;
+
+ private List ipCert;
+
+ private List vulnerability;
+
+ private List tags;
+
+ private IpInformation ipInformation;
+
+ private List extends Object> banner;
+
+ private List extends Object> httpContent;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java
new file mode 100644
index 0000000..8d479dc
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 2018-11-22
+ */
+@Data
+@TableName("scan_result")
+public class ScanResult implements Serializable {
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String ip;
+
+ private Integer flags;
+
+ private Integer opcode;
+
+ private Integer qr;
+ //权威标志位
+ private Integer aa;
+ //递归标志位
+ private Integer ra;
+
+ private Integer rcode;
+
+ private String queryName;
+
+ private String queryResponse;
+
+ private String component;
+
+ private int epoch;
+
+ private List componentList;
+ //(预留)ipv4,ipv6,dnssec,tcp,udp等
+ private Integer scanType;
+
+ private Date time;
+ @TableField(exist = false)
+ private IpInformation IpInformation;
+ @TableField(exist = false)
+ private List forwarderBanner;
+ @TableField(exist = false)
+ private Integer dnsType;
+ @TableField(exist = false)
+ private List nonstandardBanner;
+
+ @TableField(exist = false)
+ private List tags;
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java
new file mode 100644
index 0000000..b31ba3e
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java
@@ -0,0 +1,24 @@
+package com.example.modules.dns.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@TableName("vulnerability")
+public class Vulnerability implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String component;
+
+ private String vulnerability;
+
+ private Date timestamp;
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java
new file mode 100644
index 0000000..0d1eee5
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java
@@ -0,0 +1,76 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.modules.dns.domain.Result;
+import com.example.modules.dns.domain.ScanResult;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+@Repository
+public interface DnsDo53Dao extends BaseMapper {
+
+ List queryDo53Page(IPage page, @Param("params") Map params);
+
+ int do53IpCount(@Param("params") Map params);
+
+ List> do53ServiceCategoryCount(@Param("params") Map params);
+
+ List> do53ProvinceCount(@Param("params") Map params);
+
+ List> do53ProviderCount(@Param("params") Map params);
+
+ List> do53ComponentCount(@Param("params") Map params);
+
+ List> do53VulnerabilityCount(@Param("params") Map params);
+
+ List> do53CountryCount();
+
+ List> do53CountryMapCount();
+
+
+ List> do53WorldMapCount();
+
+ List> do53ChinaMapCount();
+
+ int pageCount(@Param("params") Map params);
+
+ List queryOpenRdns(@Param("params")Map params);
+
+ int getCountByDnsType(@Param("dnsType")Integer dnsType,@Param("params") Map params);
+
+ int getIndependentIpNum(@Param("dnsType")Integer dnsType, @Param("params")Map params);
+
+ List selectScanResultByUnion(IPage page, @Param("params") Map params);
+
+ Integer selectScanResultCountByUnion(@Param("params") Map params);
+
+ List> getDohAndDo53SrvCategoryCount(@Param("params") Map params);
+
+ /**
+ * 根据dnsType和其他参数统计ip省份分布
+ * @param dnsType
+ * @param params
+ * @return
+ */
+ List> getDo53ProvinceCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map params);
+
+ /**
+ * 根据dnsType和其他参数统计ip运营商分布
+ * @param dnsType
+ * @param params
+ * @return
+ */
+ List> getDo53ProviderCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map params);
+
+ List> getDo53ComponentCountByDnsType(@Param("dnsType") Integer dnsType, Map params);
+
+ Integer getDo53SrvCategoryCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map params);
+
+ List> getDo53VulnerabCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map params);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java
new file mode 100644
index 0000000..29018e6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java
@@ -0,0 +1,93 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.modules.dns.domain.DohAttribute;
+import com.example.modules.dns.domain.IpInformation;
+import com.example.modules.dns.domain.Result;
+import com.example.modules.dns.domain.ScanResult;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+@Repository
+public interface DnsDohDao extends BaseMapper {
+
+ List queryDohPage(IPage page, @Param("params") Map params);
+
+ //省份数据统计
+ List> dohProvinceCount(@Param("params") Map params);
+
+ int dohIpCount(@Param("params") Map params);
+
+ List> dohPortCount(@Param("params") Map params);
+
+ List> dohAndDo53ProvinceCount(@Param("params") Map params);
+
+ List> dohProviderCount(@Param("params") Map params);
+
+ List> dohAndDo53ProviderCount(@Param("params") Map params);
+
+ List> dohComponentCount(@Param("params") Map params);
+
+ List> dohAndDo53ComponentCount(@Param("params") Map params);
+
+ Map dohServiceCategoryCount(@Param("params") Map params);
+
+ int dohResultTotalCount(@Param("params") Map params);
+
+ List> dohVulnerabilityCount(@Param("params") Map params);
+
+ List> dohAndDo53VulnerabilityCount(@Param("params") Map params);
+
+ List> dohCountryCount();
+
+ List> dohChinaMapCount();
+
+ List getDohRepBody(String ip, Integer port, String host, Integer rounds);
+
+ List selectDohInfoByUnion(@Param("params") Map params);
+
+ Integer selectDohCountByUnion(@Param("params") Map params);
+
+ /**
+ * 查询 doh 和 do53 交集下的port ip数量
+ * @param params
+ * @return
+ */
+ List> countDohPortUnion(@Param("params") Map params);
+
+ /**
+ * 统计 doh和do53公共ip的省份分布
+ * @param params
+ * @return
+ */
+ List> getDohAndDo53ProvinceCount(@Param("params") Map params);
+
+ /**
+ * 统计 doh和do53公共ip的运营商分布
+ * @param params
+ * @return
+ */
+ List> getDohAndDo53ProviderCount(@Param("params") Map params);
+
+ /**
+ * 统计 doh和do53公共ip的组件分布
+ * @param params
+ * @return
+ */
+ List> getDohAndDo53ComponentCount(@Param("params") Map params);
+
+ /**
+ * 统计 doh 和 do53公共ip 服务类别统计
+ * @param params
+ * @return
+ */
+ Map getDohServiceCategoryCount(@Param("params") Map params);
+
+ List> getDohAndDo53VulnerabilityCount(@Param("params") Map params);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java
new file mode 100644
index 0000000..e5193e6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java
@@ -0,0 +1,20 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.modules.dns.domain.DnsType;
+import com.example.modules.dns.domain.DohAttribute;
+import com.example.modules.dns.domain.IpCert;
+import com.example.modules.dns.domain.ScanResult;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+@Repository
+public interface DnsTypeDao extends BaseMapper {
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java
new file mode 100644
index 0000000..2986981
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java
@@ -0,0 +1,20 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.modules.dns.domain.ForwardDns;
+import com.example.modules.dns.domain.ScanResult;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+@Repository
+public interface ForwardDnsDao extends BaseMapper {
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java
new file mode 100644
index 0000000..01939f6
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java
@@ -0,0 +1,32 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.modules.dns.domain.DohAttribute;
+import com.example.modules.dns.domain.IpCert;
+import com.example.modules.dns.domain.ScanResult;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+@Repository
+public interface IpCertDao extends BaseMapper {
+
+ List queryDohPage(IPage page, @Param("params") Map params);
+
+ // 国家数据统计
+ List> countryCount();
+
+ //省份数据统计
+ List> provinceCount();
+
+ // 城市数据统计
+ List> cityCount();
+
+
+ List queryDo53Page(IPage page, @Param("params") Map params);
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java
new file mode 100644
index 0000000..2ed80e3
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java
@@ -0,0 +1,27 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.modules.dns.domain.IpInformation;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+@Repository
+public interface IpInformationDao extends BaseMapper {
+
+
+ List queryIpPage(IPage page, @Param("params") Map params);
+
+ /**
+ * 根据 forward_dns中的 forwarder查询ip信息
+ * @param ip
+ * @return
+ */
+ List getIpInfoByFwd(@Param("ip")String ip,@Param("epoch")Integer epoch);
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java
new file mode 100644
index 0000000..7c050ef
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java
@@ -0,0 +1,15 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.example.modules.dns.domain.ForwardDns;
+import com.example.modules.dns.domain.NonstandardDns;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+@Mapper
+@Repository
+public interface NonstandardDnsDao extends BaseMapper {
+
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java
new file mode 100644
index 0000000..5d1c06f
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java
@@ -0,0 +1,20 @@
+package com.example.modules.dns.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.example.modules.dns.domain.DohAttribute;
+import com.example.modules.dns.domain.ScanResult;
+import com.example.modules.dns.domain.Vulnerability;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+@Repository
+public interface VulnerabilityDao extends BaseMapper {
+
+
+}
diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java
new file mode 100644
index 0000000..3aad1ca
--- /dev/null
+++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java
@@ -0,0 +1,19 @@
+package com.example.modules.dns.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.example.modules.dns.domain.DohAttribute;
+import com.example.modules.dns.domain.IpInformation;
+import com.example.utils.page.PageUtils;
+
+import java.util.List;
+import java.util.Map;
+
+public interface DnsService extends IService {
+
+
+ PageUtils queryPage(Map params);
+
+ Map