commit 3e27fc399ae4fbeb2e2344a1a5437cf23e02bc78
Author: huojin\hj <982011>
Date: Fri Jul 25 11:22:48 2025 +0800
项目初始化
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..792671a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+
+.idea/
+youchain-common/target/
+youchain-generator/target/
+youchain-logging/target/
+youchain-system/target/
+youchain-tongyong/target/
+youchain-tools/target/
+application.pid
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ca38718
--- /dev/null
+++ b/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/README.md b/README.md
new file mode 100644
index 0000000..4aba1b0
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+新框架基础模板-后端
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..5041db7
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,253 @@
+
+
+ 4.0.0
+
+ com.youchain
+ youchain
+ pom
+ 2.6
+
+
+ youchain-common
+ youchain-logging
+ youchain-system
+ youchain-tools
+ youchain-generator
+ youchain-tongyong
+
+
+ ELADMIN 后台管理
+ https://eladmin.vip
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.5.4
+
+
+
+ 2.17.0
+ 1.2.9
+ UTF-8
+ UTF-8
+ 1.8
+ 1.16
+ 2.9.2
+ 1.2.83
+ 1.2.8
+ 2.11.1
+ 1.4.2.Final
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+
+
+ org.apache.commons
+ commons-pool2
+ ${commons-pool2.version}
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+ org.bgee.log4jdbc-log4j2
+ log4jdbc-log4j2-jdbc4.1
+ ${log4jdbc.version}
+
+
+
+
+
+ com.github.xiaoymin
+ knife4j-spring-boot-starter
+ 3.0.3
+
+
+
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ ${druid.version}
+
+
+
+
+
+ net.dreamlu
+ mica-ip2region
+ 2.6.3
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.apache.poi
+ poi
+ 4.1.2
+
+
+ org.apache.poi
+ poi-ooxml
+ 4.1.2
+
+
+ xerces
+ xercesImpl
+ 2.12.2
+
+
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+ provided
+
+
+ javax.inject
+ javax.inject
+ 1
+
+
+
+
+ com.github.whvcse
+ easy-captcha
+ 1.6.2
+
+
+
+ org.apache.commons
+ commons-text
+ 1.10.0
+
+
+
+
+ nl.basjes.parse.useragent
+ yauaa
+ 6.11
+
+
+
+
+ cn.idev.excel
+ fastexcel
+ 1.2.0
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
+
+
+
+
+ public
+ aliyun nexus
+ http://maven.aliyun.com/nexus/content/groups/public/
+
+ true
+
+
+
+
+
+
+
+
+ public
+ aliyun nexus
+ http://maven.aliyun.com/nexus/content/groups/public/
+
+ true
+
+
+ false
+
+
+
+
diff --git a/youchain-common/pom.xml b/youchain-common/pom.xml
new file mode 100644
index 0000000..630c999
--- /dev/null
+++ b/youchain-common/pom.xml
@@ -0,0 +1,26 @@
+
+
+
+ youchain
+ com.youchain
+ 2.6
+
+ 4.0.0
+
+ 5.8.21
+
+
+ youchain-common
+ 公共模块
+
+
+
+
+ cn.hutool
+ hutool-all
+ ${hutool.version}
+
+
+
\ No newline at end of file
diff --git a/youchain-common/src/main/java/com/youchain/annotation/AnonymousAccess.java b/youchain-common/src/main/java/com/youchain/annotation/AnonymousAccess.java
new file mode 100644
index 0000000..2936886
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author jacky
+ * 用于标记匿名访问方法
+ */
+@Inherited
+@Documented
+@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnonymousAccess {
+
+}
diff --git a/youchain-common/src/main/java/com/youchain/annotation/DataPermission.java b/youchain-common/src/main/java/com/youchain/annotation/DataPermission.java
new file mode 100644
index 0000000..f99c6c0
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.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")
+ *
+ * @author Liu Xue
+ * @website https://eladmin.vip
+ * @date 2020-05-07
+ **/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DataPermission {
+
+ /**
+ * Entity 中的字段名称
+ */
+ String fieldName() default "";
+
+ /**
+ * Entity 中与部门关联的字段名称
+ */
+ String joinName() default "";
+}
diff --git a/youchain-common/src/main/java/com/youchain/annotation/Limit.java b/youchain-common/src/main/java/com/youchain/annotation/Limit.java
new file mode 100644
index 0000000..f44ae97
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.annotation;
+
+import com.youchain.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/youchain-common/src/main/java/com/youchain/annotation/Query.java b/youchain-common/src/main/java/com/youchain/annotation/Query.java
new file mode 100644
index 0000000..9701cb2
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/annotation/Query.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Liu Xue
+ * @date 2019-6-4 13:52:30
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Query {
+
+ // Dong ZhaoYang 2017/8/7 基本对象的属性名
+ String propName() default "";
+ // Dong ZhaoYang 2017/8/7 查询方式
+ Type type() default Type.EQUAL;
+
+ /**
+ * 连接查询的属性名,如User类中的dept
+ */
+ String joinName() default "";
+
+ /**
+ * 默认左连接
+ */
+ Join join() default Join.LEFT;
+
+ /**
+ * 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username")
+ */
+ String blurry() default "";
+
+ enum Type {
+ // jie 2019/6/4 相等
+ EQUAL
+ // Dong ZhaoYang 2017/8/7 大于等于
+ , GREATER_THAN
+ // Dong ZhaoYang 2017/8/7 小于等于
+ , LESS_THAN
+ // Dong ZhaoYang 2017/8/7 大于
+ , GREATER_THAN_NQ
+ // 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
+ //两个属性 相等
+ ,EQUAL_2
+ // 两个属性 大于等于
+ , GREATER_THAN_2
+ // 两个属性 小于等于
+ , LESS_THAN_2
+ // 两个属性 大于等于
+ , GREATER_THAN_NQ_2
+ // 两个属性 小于等于
+ , LESS_THAN_NQ_2
+ // 两个属性 不相等等于
+ , NOT_EQUAL_2
+ }
+
+ /**
+ * @author Liu Xue
+ * 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询
+ */
+ enum Join {
+ /** jie 2019-6-4 13:18:30 */
+ LEFT, RIGHT, INNER
+ }
+
+}
+
diff --git a/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousDeleteMapping.java b/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousDeleteMapping.java
new file mode 100644
index 0000000..b4ad330
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.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.youchain.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/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousGetMapping.java b/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousGetMapping.java
new file mode 100644
index 0000000..32f1e25
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.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.youchain.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/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousPatchMapping.java b/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousPatchMapping.java
new file mode 100644
index 0000000..40cdba1
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.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.youchain.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/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousPostMapping.java b/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousPostMapping.java
new file mode 100644
index 0000000..c92ed1f
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.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.youchain.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/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousPutMapping.java b/youchain-common/src/main/java/com/youchain/annotation/rest/AnonymousPutMapping.java
new file mode 100644
index 0000000..6ff1827
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.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.youchain.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/youchain-common/src/main/java/com/youchain/aspect/LimitAspect.java b/youchain-common/src/main/java/com/youchain/aspect/LimitAspect.java
new file mode 100644
index 0000000..ca21871
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.aspect;
+
+import com.google.common.collect.ImmutableList;
+import com.youchain.utils.RequestHolder;
+import com.youchain.utils.StringUtils;
+import com.youchain.annotation.Limit;
+import com.youchain.exception.BadRequestException;
+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.youchain.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/youchain-common/src/main/java/com/youchain/aspect/LimitType.java b/youchain-common/src/main/java/com/youchain/aspect/LimitType.java
new file mode 100644
index 0000000..4ac17eb
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.aspect;
+
+/**
+ * 限流枚举
+ * @author /
+ */
+public enum LimitType {
+ // 默认
+ CUSTOMER,
+ // by ip addr
+ IP
+}
diff --git a/youchain-common/src/main/java/com/youchain/base/BaseDTO.java b/youchain-common/src/main/java/com/youchain/base/BaseDTO.java
new file mode 100644
index 0000000..fd2f5a1
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/base/BaseDTO.java
@@ -0,0 +1,40 @@
+package com.youchain.base;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.sql.Timestamp;
+
+/**
+ * @author Liu Xue
+ * @date 2019年10月24日20:48:53
+ */
+@Getter
+@Setter
+public class BaseDTO implements Serializable {
+
+ private String createBy;
+
+ private String updateBy;
+
+ private Timestamp createTime;
+
+ private Timestamp updateTime;
+
+ @Override
+ public String toString() {
+ ToStringBuilder builder = new ToStringBuilder(this);
+ Field[] fields = this.getClass().getDeclaredFields();
+ try {
+ for (Field f : fields) {
+ f.setAccessible(true);
+ builder.append(f.getName(), f.get(this)).append("\n");
+ }
+ } catch (Exception e) {
+ builder.append("toString builder encounter an error");
+ }
+ return builder.toString();
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/base/BaseEntity.java b/youchain-common/src/main/java/com/youchain/base/BaseEntity.java
new file mode 100644
index 0000000..8dc15ad
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.base;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.hibernate.annotations.CreationTimestamp;
+import org.hibernate.annotations.UpdateTimestamp;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.LastModifiedBy;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+import javax.persistence.Column;
+import javax.persistence.EntityListeners;
+import javax.persistence.MappedSuperclass;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.sql.Timestamp;
+
+/**
+ * 通用字段, is_del 根据需求自行添加
+ * @author Liu Xue
+ * @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/youchain-common/src/main/java/com/youchain/base/BaseMapper.java b/youchain-common/src/main/java/com/youchain/base/BaseMapper.java
new file mode 100644
index 0000000..6ab4c35
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/base/BaseMapper.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.youchain.base;
+
+import java.util.List;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+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/youchain-common/src/main/java/com/youchain/config/AuditorConfig.java b/youchain-common/src/main/java/com/youchain/config/AuditorConfig.java
new file mode 100644
index 0000000..4347745
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.config;
+
+import com.youchain.utils.SecurityUtils;
+import org.springframework.data.domain.AuditorAware;
+import org.springframework.stereotype.Component;
+import java.util.Optional;
+
+/**
+ * @description : 设置审计
+ * @author : Dong ZhaoYang
+ * @date : 2019/10/28
+ */
+@Component("auditorAware")
+public class AuditorConfig implements AuditorAware {
+
+ /**
+ * 返回操作员标志信息
+ *
+ * @return /
+ */
+ @Override
+ public Optional getCurrentAuditor() {
+ try {
+ // 这里应根据实际业务情况获取具体信息
+ return Optional.of(SecurityUtils.getCurrentUsername());
+ }catch (Exception ignored){}
+ // 用户定时任务,或者无Token调用的情况
+ return Optional.of("System");
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/config/ElAdminProperties.java b/youchain-common/src/main/java/com/youchain/config/ElAdminProperties.java
new file mode 100644
index 0000000..a37e4d9
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Liu Xue
+ * @description
+ * @date 2021-11-22
+ **/
+@Data
+@Component
+public class ElAdminProperties {
+
+ public static Boolean ipLocal;
+
+ @Value("${ip.local-parsing}")
+ public void setIpLocal(Boolean ipLocal) {
+ ElAdminProperties.ipLocal = ipLocal;
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/config/ElPermissionConfig.java b/youchain-common/src/main/java/com/youchain/config/ElPermissionConfig.java
new file mode 100644
index 0000000..372d4da
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.config;
+
+import com.youchain.utils.SecurityUtils;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.stereotype.Service;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Liu Xue
+ */
+@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/youchain-common/src/main/java/com/youchain/config/FileProperties.java b/youchain-common/src/main/java/com/youchain/config/FileProperties.java
new file mode 100644
index 0000000..f24b4e1
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.config;
+
+import com.youchain.utils.ElAdminConstant;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Liu Xue
+ */
+@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/youchain-common/src/main/java/com/youchain/config/RedisConfig.java b/youchain-common/src/main/java/com/youchain/config/RedisConfig.java
new file mode 100644
index 0000000..06f454e
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/config/RedisConfig.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.config;
+
+import cn.hutool.core.lang.Assert;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cache.Cache;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.CacheErrorHandler;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import reactor.util.annotation.Nullable;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-24
+ */
+@Slf4j
+@Configuration
+@EnableCaching
+@ConditionalOnClass(RedisOperations.class)
+@EnableConfigurationProperties(RedisProperties.class)
+public class RedisConfig extends CachingConfigurerSupport {
+
+ /**
+ * 设置 redis 数据默认过期时间,默认2小时
+ * 设置@cacheable 序列化方式
+ */
+ @Bean
+ public RedisCacheConfiguration redisCacheConfiguration(){
+ FastJsonRedisSerializer 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);
+ // fastjson 升级到 1.2.83 后需要指定序列化白名单
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.domain");
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.service.dto");
+ ParserConfig.getGlobalInstance().addAccept("com.youchain");
+
+
+ // 模块内的实体类
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.modules.mnt.domain");
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.modules.quartz.domain");
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.modules.system.domain");
+ // 模块内的 Dto
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.modules.mnt.service.dto");
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.modules.quartz.service.dto");
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.modules.security.service.dto");
+ ParserConfig.getGlobalInstance().addAccept("com.youchain.modules.system.service.dto");
+ // key的序列化采用StringRedisSerializer
+ template.setKeySerializer(new StringRedisSerializer());
+ template.setHashKeySerializer(new StringRedisSerializer());
+ template.setConnectionFactory(redisConnectionFactory);
+ return template;
+ }
+
+ /**
+ * 自定义缓存key生成策略,默认将使用该策略
+ */
+ @Bean
+ @Override
+ public KeyGenerator keyGenerator() {
+ return (target, method, params) -> {
+ Map container = new HashMap<>(8);
+ Class> targetClassClass = target.getClass();
+ // 类地址
+ container.put("class",targetClassClass.toGenericString());
+ // 方法名称
+ container.put("methodName",method.getName());
+ // 包名称
+ container.put("package",targetClassClass.getPackage());
+ // 参数列表
+ for (int i = 0; i < params.length; i++) {
+ container.put(String.valueOf(i),params[i]);
+ }
+ // 转为JSON字符串
+ String jsonString = JSON.toJSONString(container);
+ // 做SHA256 Hash计算,得到一个SHA256摘要作为Key
+ return DigestUtils.sha256Hex(jsonString);
+ };
+ }
+
+ @Bean
+ @Override
+ public CacheErrorHandler errorHandler() {
+ // 异常处理,当Redis发生异常时,打印日志,但是程序正常走
+ log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
+ return new CacheErrorHandler() {
+ @Override
+ public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
+ log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
+ }
+
+ @Override
+ public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
+ log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
+ }
+
+ @Override
+ public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
+ log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
+ }
+
+ @Override
+ public void handleCacheClearError(RuntimeException e, Cache cache) {
+ log.error("Redis occur handleCacheClearError:", e);
+ }
+ };
+ }
+
+}
+
+/**
+ * Value 序列化
+ *
+ * @author /
+ * @param
+ */
+@Slf4j
+ 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/youchain-common/src/main/java/com/youchain/config/RsaProperties.java b/youchain-common/src/main/java/com/youchain/config/RsaProperties.java
new file mode 100644
index 0000000..2b8c27e
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/config/RsaProperties.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Liu Xue
+ * @website https://eladmin.vip
+ * @description
+ * @date 2020-05-18
+ **/
+@Data
+@Component
+public class RsaProperties {
+ public static String licenseKey;
+ public static String privateKey;
+
+ @Value("${rsa.private_key}")
+ public void setPrivateKey(String privateKey) {
+ RsaProperties.privateKey = privateKey;
+ }
+
+ @Value("${rsa.licenseKey}")
+ public void setLicenseKey(String privateKey) {
+ RsaProperties.licenseKey = privateKey;
+ }
+}
\ No newline at end of file
diff --git a/youchain-common/src/main/java/com/youchain/config/SwaggerConfig.java b/youchain-common/src/main/java/com/youchain/config/SwaggerConfig.java
new file mode 100644
index 0000000..0240bdb
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/config/SwaggerConfig.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.config;
+
+import cn.hutool.core.collection.CollUtil;
+import com.fasterxml.classmate.TypeResolver;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.data.domain.Pageable;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.schema.AlternateTypeRule;
+import springfox.documentation.schema.AlternateTypeRuleConvention;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.service.AuthorizationScope;
+import springfox.documentation.service.SecurityReference;
+import springfox.documentation.service.SecurityScheme;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+import static springfox.documentation.schema.AlternateTypeRules.newRule;
+
+/**
+ * api页面 /doc.html
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+ @Value("${jwt.header}")
+ private String tokenHeader;
+
+ @Value("${swagger.enabled}")
+ private Boolean enabled;
+
+ @Bean
+ @SuppressWarnings("all")
+ public Docket createRestApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .enable(enabled)
+ .pathMapping("/")
+ .apiInfo(apiInfo())
+ .select()
+ .paths(PathSelectors.regex("^(?!/error).*"))
+ .paths(PathSelectors.any())
+ .build()
+ //添加登陆认证
+ .securitySchemes(securitySchemes())
+ .securityContexts(securityContexts());
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder()
+ .description("后台管理")
+ .title("接口文档")
+ .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())
+ .operationSelector(o->o.requestMappingPattern().matches("^(?!/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 CollUtil.newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));
+ }
+ };
+ }
+
+ @ApiModel
+ @Data
+ private static class Page {
+ @ApiModelProperty("页码 (0..N)")
+ private Integer page;
+
+ @ApiModelProperty("每页显示的数目")
+ private Integer size;
+
+ @ApiModelProperty("以下列格式排序标准:property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件:如:id,asc")
+ private List sort;
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/exception/BadConfigurationException.java b/youchain-common/src/main/java/com/youchain/exception/BadConfigurationException.java
new file mode 100644
index 0000000..08fb74a
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.exception;
+
+/**
+ * 统一关于错误配置信息 异常
+ *
+ * @author: liaojinlong
+ * @date: 2020/6/10 18:06
+ */
+public class BadConfigurationException extends RuntimeException {
+ /**
+ * Constructs a new runtime exception with {@code null} as its
+ * detail message. The cause is not initialized, and may subsequently be
+ * initialized by a call to {@link #initCause}.
+ */
+ public BadConfigurationException() {
+ super();
+ }
+
+ /**
+ * Constructs a new runtime exception with the specified detail message.
+ * The cause is not initialized, and may subsequently be initialized by a
+ * call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for
+ * later retrieval by the {@link #getMessage()} method.
+ */
+ public BadConfigurationException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new runtime exception with the specified detail message and
+ * cause. 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/youchain-common/src/main/java/com/youchain/exception/BadRequestException.java b/youchain-common/src/main/java/com/youchain/exception/BadRequestException.java
new file mode 100644
index 0000000..686b504
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/exception/BadRequestException.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.youchain.exception;
+
+import lombok.Getter;
+import org.springframework.http.HttpStatus;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-23
+ * 统一异常处理
+ */
+@Getter
+public class BadRequestException extends RuntimeException{
+
+ private Integer status = BAD_REQUEST.value();
+
+ public BadRequestException(String msg){
+ super(msg);
+ }
+
+ public BadRequestException(HttpStatus status,String msg){
+ super(msg);
+ this.status = status.value();
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/exception/EntityExistException.java b/youchain-common/src/main/java/com/youchain/exception/EntityExistException.java
new file mode 100644
index 0000000..0975358
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/exception/EntityExistException.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.exception;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+public class EntityExistException extends RuntimeException {
+
+ public EntityExistException(Class clazz, String field, String val) {
+ super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
+ }
+
+ private static String generateMessage(String entity, String field, String val) {
+ return StringUtils.capitalize(entity)
+ + " with " + field + " "+ val + " existed";
+ }
+}
\ No newline at end of file
diff --git a/youchain-common/src/main/java/com/youchain/exception/EntityNotFoundException.java b/youchain-common/src/main/java/com/youchain/exception/EntityNotFoundException.java
new file mode 100644
index 0000000..1e7bad8
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/exception/EntityNotFoundException.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.exception;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+public class EntityNotFoundException extends RuntimeException {
+
+ public EntityNotFoundException(Class clazz, String field, String val) {
+ super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
+ }
+
+ private static String generateMessage(String entity, String field, String val) {
+ return StringUtils.capitalize(entity)
+ + " with " + field + " "+ val + " does not exist";
+ }
+}
\ No newline at end of file
diff --git a/youchain-common/src/main/java/com/youchain/exception/handler/ApiError.java b/youchain-common/src/main/java/com/youchain/exception/handler/ApiError.java
new file mode 100644
index 0000000..3756b2a
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/exception/handler/ApiError.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.youchain.exception.handler;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import java.time.LocalDateTime;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+@Data
+public class ApiError {
+
+ private Integer status = 400;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime timestamp;
+ private String message;
+
+ public 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;
+ }
+
+ public static ApiError errorJosn(Integer status, String message){
+ ApiError apiError = new ApiError();
+ apiError.setStatus(status);
+ apiError.setMessage(message);
+ apiError.setTimestamp(LocalDateTime.now());
+ return apiError;
+ }
+}
+
+
diff --git a/youchain-common/src/main/java/com/youchain/exception/handler/ApiResult.java b/youchain-common/src/main/java/com/youchain/exception/handler/ApiResult.java
new file mode 100644
index 0000000..21e2e31
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/exception/handler/ApiResult.java
@@ -0,0 +1,43 @@
+package com.youchain.exception.handler;
+
+import lombok.Data;
+
+@Data
+public class ApiResult {
+ private Object data;//数据
+ private String message;//内容
+ private int status;//编码
+
+ public static ApiResult fail() {
+
+ return result(400, "操作失败!", null);
+ }
+
+ public static ApiResult fail(int code, String msg, Object data) {
+ return result(code, msg, data);
+ }
+
+ public static ApiResult success() {
+ return result(200, "操作成功!", null);
+ }
+
+ public static ApiResult success(Object data) {
+ return result(200, "操作成功!", data);
+ }
+
+ public static ApiResult success(String msg, Object data) {
+ return result(200, msg, data);
+ }
+
+ public static ApiResult success(int status, String msg, Object data) {
+ return result(status, msg, data);
+ }
+
+ public static ApiResult result(int status, String message, Object data) {
+ ApiResult rs = new ApiResult();
+ rs.setStatus(status);
+ rs.setMessage(message);
+ rs.setData(data);
+ return rs;
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/exception/handler/GlobalExceptionHandler.java b/youchain-common/src/main/java/com/youchain/exception/handler/GlobalExceptionHandler.java
new file mode 100644
index 0000000..a8957ff
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/exception/handler/GlobalExceptionHandler.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.exception.handler;
+
+import com.youchain.exception.BadRequestException;
+import com.youchain.exception.EntityExistException;
+import com.youchain.exception.EntityNotFoundException;
+import com.youchain.utils.ThrowableUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.validation.FieldError;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import static org.springframework.http.HttpStatus.*;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+@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));
+ ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
+ String message = objectError.getDefaultMessage();
+ if (objectError instanceof FieldError) {
+ message = ((FieldError) objectError).getField() + ": " + message;
+ }
+ return buildResponseEntity(ApiError.error(message));
+ }
+
+ /**
+ * 统一返回
+ */
+ private ResponseEntity buildResponseEntity(ApiError apiError) {
+ return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus()));
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/CacheKey.java b/youchain-common/src/main/java/com/youchain/utils/CacheKey.java
new file mode 100644
index 0000000..b3caf41
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/CacheKey.java
@@ -0,0 +1,60 @@
+/*
+ * 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.youchain.utils;
+
+/**
+ * @author: liaojinlong
+ * @date: 2020/6/11 15:49
+ * @apiNote: 关于缓存的Key集合
+ */
+public interface CacheKey {
+
+ /**
+ * 用户
+ */
+ String USER_ID = "user::id:";
+ /**
+ * 数据
+ */
+ String DATA_USER = "data::user:";
+ /**
+ * 菜单
+ */
+ String MENU_ID = "menu::id:";
+ String MENU_USER = "menu::user:";
+ /**
+ * 角色授权
+ */
+ String ROLE_AUTH = "role::auth:";
+ /**
+ * 角色信息
+ */
+ String ROLE_ID = "role::id:";
+ /**
+ * 部门
+ */
+ String DEPT_ID = "dept::id:";
+ /**
+ * 岗位
+ */
+ String JOB_ID = "job::id:";
+ /**
+ * 数据字典
+ */
+ String DICT_NAME = "dict::name:";
+
+ String BOM_ACCOUNT_NAME = "bomAccount::id:";
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/CallBack.java b/youchain-common/src/main/java/com/youchain/utils/CallBack.java
new file mode 100644
index 0000000..2c093bb
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils;
+
+/**
+ * @author: liaojinlong
+ * @date: 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/youchain-common/src/main/java/com/youchain/utils/CloseUtil.java b/youchain-common/src/main/java/com/youchain/utils/CloseUtil.java
new file mode 100644
index 0000000..a4e014b
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils;
+
+import java.io.Closeable;
+
+/**
+ * @author Liu Xue
+ * @website https://eladmin.vip
+ * @description 用于关闭各种连接,缺啥补啥
+ * @date 2021-03-05
+ **/
+public class CloseUtil {
+
+ public static void close(Closeable closeable) {
+ if (null != closeable) {
+ try {
+ closeable.close();
+ } catch (Exception e) {
+ // 静默关闭
+ }
+ }
+ }
+
+ public static void close(AutoCloseable closeable) {
+ if (null != closeable) {
+ try {
+ closeable.close();
+ } catch (Exception e) {
+ // 静默关闭
+ }
+ }
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/CodeForYmYtil.java b/youchain-common/src/main/java/com/youchain/utils/CodeForYmYtil.java
new file mode 100644
index 0000000..1b77da6
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/CodeForYmYtil.java
@@ -0,0 +1,91 @@
+package com.youchain.utils;
+
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+public class CodeForYmYtil {
+ private static String key_time_type="yyMMdd";
+ public void ce(){
+ new Thread(()->{
+ CodeForYmYtil codeForYmYtil=new CodeForYmYtil();
+ for (int i = 0; i < 100; i++) {
+ String code = codeForYmYtil.CodeForYmYtil("ce",5);
+ }
+ }).start();
+ new Thread(()->{
+ CodeForYmYtil codeForYmYtil=new CodeForYmYtil();
+ for (int i = 0; i < 100; i++) {
+ String code = codeForYmYtil.CodeForYmYtil("ce",5);
+ }
+ }).start();
+ new Thread(()->{
+ CodeForYmYtil codeForYmYtil=new CodeForYmYtil();
+ for (int i = 0; i < 100; i++) {
+ String code = codeForYmYtil.CodeForYmYtil("ce",5);
+ }
+ }).start();
+ new Thread(()->{
+ CodeForYmYtil codeForYmYtil=new CodeForYmYtil();
+ for (int i = 0; i < 100; i++) {
+ String code = codeForYmYtil.CodeForYmYtil("ce",5);
+ }
+ }).start();
+ }
+ public static synchronized String CodeForYmYtil(String key_code, int len){
+ String code="";
+ String key_time = new SimpleDateFormat(key_time_type).format(Calendar.getInstance().getTime());
+ String key=key_code+key_time;
+ String redisHost = "127.0.0.1";
+ int redisPort = 6379;
+ RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
+ LettuceConnectionFactory factory = new LettuceConnectionFactory(config);
+ factory.afterPropertiesSet();
+ RedisTemplate redisTemplate = new RedisTemplate<>();
+ redisTemplate.setConnectionFactory(factory);
+ redisTemplate.afterPropertiesSet();
+
+ ValueOperations ops = redisTemplate.opsForValue();
+ String value;
+// value = ops.get(key).toString();
+
+ if (ops.get(key)==null||ops.get(key).equals("")){
+ ops.set(key, "0");
+ }
+ value = (Integer.valueOf(ops.get(key).toString())+1)+"";
+ ops.set(key, value);
+ while (value.length()();
+ redisTemplate.setConnectionFactory(factory);
+ redisTemplate.afterPropertiesSet();
+ ValueOperations ops = redisTemplate.opsForValue();
+
+ String value = ops.get("pd")+"";
+ System.out.println(":"+value);
+ factory.destroy();
+ System.out.println("poiuytrew");*/
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/DateUtil.java b/youchain-common/src/main/java/com/youchain/utils/DateUtil.java
new file mode 100644
index 0000000..bebfdf8
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/DateUtil.java
@@ -0,0 +1,266 @@
+/*
+ * 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.youchain.utils;
+
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * @author: liaojinlong
+ * @date: 2020/6/11 16:28
+ * @apiNote: JDK 8 新日期类 格式化与字符串转换 工具类
+ */
+public class DateUtil {
+
+ public static final DateTimeFormatter DFY_MD_HMS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+ public static final DateTimeFormatter DFY_MD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ public static final DateTimeFormatter DFY_MD_HM = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
+
+ private static SimpleDateFormat ymd = new SimpleDateFormat("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);
+ }
+
+
+ public static Date ymd_date(String fomart) {
+ try {
+ return ymd.parse(fomart);
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+ /**
+ * 日期格式化 yyyy-MM-dd
+ *
+ * @param localDateTime /
+ * @return /
+ */
+ public static String localDateTimeFormatyMd(LocalDateTime localDateTime) {
+
+ return DFY_MD.format(localDateTime);
+ }
+
+ public static String dateYmd(Date date) {
+ return ymd.format(date);
+ }
+
+ //按周天生成批次
+ public static String dateYmdz() {
+ Calendar calendar = Calendar.getInstance();
+ int year = calendar.get(Calendar.YEAR);
+ int month = calendar.get(Calendar.MONTH) + 1;
+ int day = calendar.get(Calendar.DAY_OF_MONTH);
+ String z="01-07";
+ if(day<=7){
+ z="01-07";
+ }else if(day>7 && day<=14){
+ z="08-14";
+ }else if(day>14 && day<=21){
+ z="15-21";
+ }else if(day>21 && day<=28){
+ z="22-28";
+ }else if(day>28){
+ z="29-31";
+ }
+ return year+"-"+month+"-"+z;
+ }
+
+ public static String formatChageDay(Date date, String type, int value) {
+ Calendar cal = new java.util.GregorianCalendar();
+ cal.setTime(date);
+ if (type.equals("DAY")) {
+ cal.add(Calendar.DATE , value);
+ }
+ if (type.equals("HOUR")) {
+ cal.add(Calendar.HOUR, value);
+ }
+ if (type.equals("MINUTE")) {
+ cal.add(Calendar.MINUTE, value);
+ }
+ if (type.equals("SECOND")) {
+ cal.add(Calendar.SECOND, value);
+ }
+ return ymd.format(cal.getTime());
+ }
+
+ public static Timestamp getBatchTime(int value,Date date) {
+ Calendar cal = new java.util.GregorianCalendar();
+ cal.setTime(date);
+ cal.set(Calendar.HOUR_OF_DAY,8);
+ cal.set(Calendar.MINUTE,30);
+ cal.set(Calendar.MILLISECOND,0);
+ cal.add(Calendar.MINUTE, value);
+ int hour = cal.get(Calendar.HOUR_OF_DAY);
+ int minute = cal.get(Calendar.MINUTE);
+ //11:30-12:30休息
+ if(hour>11||(hour==11&&minute>=30)){
+ cal.add(Calendar.HOUR, 1);
+ }
+// //17:30-18:30休息
+// hour = cal.get(Calendar.HOUR_OF_DAY);
+// if(hour>17||(hour==17&&minute>=30)){
+// cal.add(Calendar.HOUR, 1);
+// }
+ return new Timestamp(cal.getTime().getTime());
+ }
+
+ /**
+ * 字符串转 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));
+ }
+
+ /**
+ *获取两个字符串计算出小时
+ * @param
+ * @return
+ */
+ public static long hoursBetween(String startDateTimeStr,String endDateTimeStr) {
+ // 解析日期时间字符串为 LocalDateTime 对象
+ LocalDateTime startDateTime = LocalDateTime.parse(startDateTimeStr, DFY_MD_HM);
+ LocalDateTime endDateTime = LocalDateTime.parse(endDateTimeStr, DFY_MD_HM);
+ // 计算时间差
+ Duration duration = Duration.between(startDateTime, endDateTime);
+ long hours = duration.toHours(); // 将时间差转换为小时
+ return hours;
+ }
+
+ /**
+ *比较两个日期大小
+ * @param
+ * @return
+ */
+ public static int dateComparison (Date date1,Date date2) {
+ int comparison = date1.compareTo(date2);
+ return comparison;
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/ElAdminConstant.java b/youchain-common/src/main/java/com/youchain/utils/ElAdminConstant.java
new file mode 100644
index 0000000..9508000
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/ElAdminConstant.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.youchain.utils;
+
+/**
+ * 常用静态常量
+ *
+ * @author Liu Xue
+ * @date 2018-12-26
+ */
+public class ElAdminConstant {
+
+ /**
+ * 用于IP定位转换
+ */
+ public static final String REGION = "内网IP|内网IP";
+ /**
+ * win 系统
+ */
+ public static final String WIN = "win";
+
+ /**
+ * mac 系统
+ */
+ public static final String MAC = "mac";
+
+ /**
+ * 常用接口
+ */
+ public static class Url {
+ // IP归属地查询
+ public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?ip=%s&json=true";
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/EncryptUtils.java b/youchain-common/src/main/java/com/youchain/utils/EncryptUtils.java
new file mode 100644
index 0000000..f765c50
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 加密
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+
+public class EncryptUtils {
+
+ private static final String STR_PARAM = "Passw0rd";
+
+ private static Cipher cipher;
+
+ private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8));
+
+ private static DESKeySpec getDesKeySpec(String source) throws Exception {
+ if (source == null || source.length() == 0){
+ return null;
+ }
+ cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
+ String strKey = "Passw0rd";
+ return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * 对称加密
+ */
+ public static String desEncrypt(String source) throws Exception {
+ DESKeySpec desKeySpec = getDesKeySpec(source);
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+ SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV);
+ return byte2hex(
+ cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase();
+ }
+
+ /**
+ * 对称解密
+ */
+ public static String desDecrypt(String source) throws Exception {
+ byte[] src = hex2byte(source.getBytes(StandardCharsets.UTF_8));
+ DESKeySpec desKeySpec = getDesKeySpec(source);
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+ SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, IV);
+ byte[] retByte = cipher.doFinal(src);
+ return new String(retByte);
+ }
+
+ private static String byte2hex(byte[] inStr) {
+ String stmp;
+ StringBuilder out = new StringBuilder(inStr.length * 2);
+ for (byte b : inStr) {
+ stmp = Integer.toHexString(b & 0xFF);
+ if (stmp.length() == 1) {
+ // 如果是0至F的单位字符串,则添加0
+ out.append("0").append(stmp);
+ } else {
+ out.append(stmp);
+ }
+ }
+ return out.toString();
+ }
+
+ private static byte[] hex2byte(byte[] b) {
+ int size = 2;
+ if ((b.length % size) != 0){
+ throw new IllegalArgumentException("长度不是偶数");
+ }
+ byte[] b2 = new byte[b.length / 2];
+ for (int n = 0; n < b.length; n += size) {
+ String item = new String(b, n, 2);
+ b2[n / 2] = (byte) Integer.parseInt(item, 16);
+ }
+ return b2;
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/FileUtil.java b/youchain-common/src/main/java/com/youchain/utils/FileUtil.java
new file mode 100644
index 0000000..8e4e434
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/FileUtil.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.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.youchain.config.FileProperties;
+import com.youchain.exception.BadRequestException;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.security.MessageDigest;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * File工具类,扩展 hutool 工具包
+ *
+ * @author Liu Xue
+ * @date 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 APK = "APK";
+ public static final String ZIP = "ZIP";
+ 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 = "-" +SecurityUtils.getCurrentUsername()+ "-" + 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 Exception {
+ log.error("list:"+list.size());
+ if(list.size()>0){
+ if(list.get(0).keySet().size()<=0){
+ throw new BadRequestException("请先保存配置");
+ }
+ }else{
+ throw new BadRequestException("导出数据长度为0");
+ }
+
+ FileProperties properties=SpringContextHolder.getBean(FileProperties.class);
+ String tempPath=properties.getPath().getPath()+"downexcel\\"+IdUtil.fastSimpleUUID() + ".xlsx";
+ File file = new File(tempPath);
+ log.error(tempPath);
+
+ //BigExcelWriter writer = ExcelUtil.getBigWriter(file);
+ MyExcelWriter writer =MyExcelWriter.getBigWriter(file);
+ // 一次性写出内容,使用默认样式,强制输出标题
+ writer.write(list, true);
+ //列宽自适应
+ writer.autoSizeColumnAll();
+ //response为HttpServletResponse对象
+ response.setContentType("application/vnd.ms-excel;charset=utf-8");
+ //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
+ response.setHeader("Content-Disposition","attachment;filename=file.xls");
+ 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";
+ String apk = "apk";
+ String zip = "zip rar 7z";
+ if (apk.contains(type)) {
+ return APK;
+ }else if (zip.contains(type)) {
+ return ZIP;
+ }else 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/youchain-common/src/main/java/com/youchain/utils/HttpPostUtil.java b/youchain-common/src/main/java/com/youchain/utils/HttpPostUtil.java
new file mode 100644
index 0000000..c58914c
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/HttpPostUtil.java
@@ -0,0 +1,49 @@
+package com.youchain.utils;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import org.apache.commons.compress.utils.IOUtils;
+
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+public class HttpPostUtil {
+ public static String sendPostReq(String api_url, String request){
+ InputStream instr = null;
+ String str = "";
+ try {
+ URL url = new URL(api_url);
+ URLConnection urlCon = url.openConnection();
+ urlCon.setConnectTimeout(3000);
+ byte[] xmlData = request.getBytes();
+ urlCon.setDoOutput(true);
+ urlCon.setDoInput(true);
+ urlCon.setUseCaches(false);
+ urlCon.setRequestProperty("content-Type", "application/json");
+ urlCon.setRequestProperty("charset", "UTF-8");
+ urlCon.setRequestProperty("Content-length", String.valueOf(xmlData.length));
+ DataOutputStream printout = new DataOutputStream(urlCon.getOutputStream());
+ printout.write(xmlData);
+ printout.flush();
+ printout.close();
+ instr = urlCon.getInputStream();
+ byte[] bis = IOUtils.toByteArray(instr);
+ String ResponseString = new String(bis, "UTF-8");
+ if ((ResponseString == null) || ("".equals(ResponseString.trim()))) {
+ System.out.println("返回空");
+ }
+ str = ResponseString;
+ }catch (Exception e){
+ throw new Error(e.getMessage());
+ }
+ /*JSONObject jsonObject=new JSONObject();
+ jsonObject.accumulate("code", "0");
+ jsonObject.accumulate("message", "");
+ jsonObject.accumulate("success", true);
+ jsonObject.accumulate("data", "");
+ str= JSONUtil.toJsonStr(jsonObject.toString());*/
+ return str;
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/MyExcelWriter.java b/youchain-common/src/main/java/com/youchain/utils/MyExcelWriter.java
new file mode 100644
index 0000000..2b51de8
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/MyExcelWriter.java
@@ -0,0 +1,42 @@
+package com.youchain.utils;
+
+import cn.hutool.core.exceptions.DependencyException;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.poi.excel.BigExcelWriter;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+
+import java.io.File;
+
+public class MyExcelWriter extends BigExcelWriter {
+ public static MyExcelWriter getBigWriter(File file) {
+ try {
+ return new MyExcelWriter(file);
+ } catch (NoClassDefFoundError var1) {
+ throw new DependencyException((Throwable) ObjectUtil.defaultIfNull(var1.getCause(), var1), "You need to add dependency of 'poi-ooxml' to your project, and version >= 4.1.2", new Object[0]);
+ }
+ }
+
+ public MyExcelWriter(File file){
+ super(file);
+ }
+
+ @Override
+ public BigExcelWriter autoSizeColumnAll() {
+ final SXSSFSheet sheet = (SXSSFSheet)this.sheet;
+ sheet.trackAllColumnsForAutoSizing();
+ super.autoSizeColumnAll();
+ for (int i = 0; i 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/youchain-common/src/main/java/com/youchain/utils/QueryHelp.java b/youchain-common/src/main/java/com/youchain/utils/QueryHelp.java
new file mode 100644
index 0000000..0321d49
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/QueryHelp.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.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.youchain.annotation.DataPermission;
+import com.youchain.annotation.Query;
+import javax.persistence.criteria.*;
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * @author Liu Xue
+ * @date 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 GREATER_THAN_NQ:
+ list.add(cb.greaterThan(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);
+ if(between.size() == 2){
+ list.add(cb.between(getExpression(attributeName, join, root).as((Class extends Comparable>) between.get(0).getClass()),
+ (Comparable) between.get(0), (Comparable) between.get(1)));
+ }
+ break;
+ case GREATER_THAN_2:
+ list.add(cb.greaterThanOrEqualTo(root.get(attributeName), root.get((String)val)));
+ break;
+ case LESS_THAN_2:_THAN_2:
+ list.add(cb.lessThanOrEqualTo(root.get(attributeName), root.get((String)val)));
+ break;
+ case GREATER_THAN_NQ_2:
+ list.add(cb.greaterThan(root.get(attributeName), root.get((String)val)));
+ break;
+ case LESS_THAN_NQ_2:
+ list.add(cb.lessThan(root.get(attributeName), root.get((String)val)));
+ break;
+ case EQUAL_2:
+ list.add(cb.equal(root.get(attributeName), root.get((String)val)));
+ break;
+ case NOT_EQUAL_2:
+ list.add(cb.notEqual(root.get(attributeName), root.get((String)val)));
+ 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/youchain-common/src/main/java/com/youchain/utils/RedisUtils.java b/youchain-common/src/main/java/com/youchain/utils/RedisUtils.java
new file mode 100644
index 0000000..4af9a59
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/RedisUtils.java
@@ -0,0 +1,741 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.utils;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author /
+ */
+@Component
+@SuppressWarnings({"unchecked", "all"})
+public class RedisUtils {
+ private static final Logger log = LoggerFactory.getLogger(RedisUtils.class);
+ private RedisTemplate redisTemplate;
+ @Value("${jwt.online-key}")
+ private String onlineKey;
+
+ public RedisUtils(RedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ this.redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+ this.redisTemplate.setKeySerializer(new StringRedisSerializer());
+ this.redisTemplate.setStringSerializer(new StringRedisSerializer());
+ }
+
+ /**
+ * 指定缓存失效时间
+ *
+ * @param key 键
+ * @param time 时间(秒)
+ */
+ public boolean expire(String key, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.expire(key, time, TimeUnit.SECONDS);
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 指定缓存失效时间
+ *
+ * @param key 键
+ * @param time 时间(秒)
+ * @param timeUnit 单位
+ */
+ public boolean expire(String key, long time, TimeUnit timeUnit) {
+ try {
+ if (time > 0) {
+ redisTemplate.expire(key, time, timeUnit);
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 根据 key 获取过期时间
+ *
+ * @param key 键 不能为null
+ * @return 时间(秒) 返回0代表为永久有效
+ */
+ public long getExpire(Object key) {
+ return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 查找匹配key
+ *
+ * @param pattern key
+ * @return /
+ */
+ public List 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) {
+ if (redisTemplate.hasKey(key))
+ keySet.add(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) {
+ try{
+ Object value=redisTemplate.opsForValue().get(key);
+ return value == null ? null :value ;
+ }catch (Exception e){
+ return null;
+ }
+
+ }
+
+ public Object get(String key,Object def) {
+ try{
+ Object value=redisTemplate.opsForValue().get(key);
+ return value == null ? def :value ;
+ }catch (Exception e){
+ return def;
+ }
+
+ }
+
+ /**
+ * 批量获取
+ *
+ * @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);
+ }
+
+ public Object hget(String key, String item,Object def) {
+ try {
+ Object value = redisTemplate.opsForHash().get(key, item);
+ return value == null ? def:value;
+ }catch (Exception e){
+ return def;
+ }
+ }
+
+ /**
+ * 获取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("--------------------------------------------");
+ }
+
+ public Set getAllKey(String pattern){
+ return redisTemplate.keys(pattern);
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/RequestHolder.java b/youchain-common/src/main/java/com/youchain/utils/RequestHolder.java
new file mode 100644
index 0000000..0ed1fc4
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+/**
+ * 获取 HttpServletRequest
+ * @author Liu Xue
+ * @date 2018-11-24
+ */
+public class RequestHolder {
+
+ public static HttpServletRequest getHttpServletRequest() {
+ return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/RsaUtils.java b/youchain-common/src/main/java/com/youchain/utils/RsaUtils.java
new file mode 100644
index 0000000..4782a7c
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/RsaUtils.java
@@ -0,0 +1,198 @@
+package com.youchain.utils;
+
+import org.apache.commons.codec.binary.Base64;
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * @author https://www.cnblogs.com/nihaorz/p/10690643.html
+ * @description Rsa 工具类,公钥私钥生成,加解密
+ * @date 2020-05-18
+ **/
+public class RsaUtils {
+
+ private static final String SRC = "123456";
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("\n");
+ RsaKeyPair keyPair = generateKeyPair();
+ System.out.println("公钥:" + keyPair.getPublicKey());
+ System.out.println("私钥:" + keyPair.getPrivateKey());
+ System.out.println("\n");
+ test1(keyPair);
+ System.out.println("\n");
+ test2(keyPair);
+ System.out.println("\n");
+ }
+
+ /**
+ * 公钥加密私钥解密
+ */
+ private static void test1(RsaKeyPair keyPair) throws Exception {
+ System.out.println("***************** 公钥加密私钥解密开始 *****************");
+ String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC);
+ String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1);
+ System.out.println("加密前:" + RsaUtils.SRC);
+ System.out.println("加密后:" + text1);
+ System.out.println("解密后:" + text2);
+ if (RsaUtils.SRC.equals(text2)) {
+ System.out.println("解密字符串和原始字符串一致,解密成功");
+ } else {
+ System.out.println("解密字符串和原始字符串不一致,解密失败");
+ }
+ System.out.println("***************** 公钥加密私钥解密结束 *****************");
+ }
+
+ /**
+ * 私钥加密公钥解密
+ * @throws Exception /
+ */
+ private static void test2(RsaKeyPair keyPair) throws Exception {
+ System.out.println("***************** 私钥加密公钥解密开始 *****************");
+ String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC);
+ String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1);
+ System.out.println("加密前:" + RsaUtils.SRC);
+ System.out.println("加密后:" + text1);
+ System.out.println("解密后:" + text2);
+ if (RsaUtils.SRC.equals(text2)) {
+ System.out.println("解密字符串和原始字符串一致,解密成功");
+ } else {
+ System.out.println("解密字符串和原始字符串不一致,解密失败");
+ }
+ System.out.println("***************** 私钥加密公钥解密结束 *****************");
+ }
+
+ /**
+ * 公钥解密
+ *
+ * @param publicKeyText 公钥
+ * @param text 待解密的信息
+ * @return /
+ * @throws Exception /
+ */
+ public static String decryptByPublicKey(String publicKeyText, String text) throws Exception {
+ X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.DECRYPT_MODE, publicKey);
+ byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text));
+ return new String(result);
+ }
+
+ /**
+ * 私钥加密
+ *
+ * @param privateKeyText 私钥
+ * @param text 待加密的信息
+ * @return /
+ * @throws Exception /
+ */
+ public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
+ PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText.trim()));
+ 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/youchain-common/src/main/java/com/youchain/utils/SecurityUtils.java b/youchain-common/src/main/java/com/youchain/utils/SecurityUtils.java
new file mode 100644
index 0000000..8f8bd86
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/SecurityUtils.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.utils;
+
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+import com.youchain.exception.BadRequestException;
+import com.youchain.utils.enums.DataScopeEnum;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import java.util.List;
+
+/**
+ * 获取当前登录的用户
+ * @author Liu Xue
+ * @date 2019-01-17
+ */
+@Slf4j
+public class SecurityUtils {
+
+ /**
+ * 获取当前登录的用户
+ * @return UserDetails
+ */
+ public static UserDetails getCurrentUser() {
+ UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class);
+ return userDetailsService.loadUserByUsername(getCurrentUsername());
+ }
+
+ /**
+ * 获取系统用户名称
+ *
+ * @return 系统用户名称
+ */
+ public static String getCurrentUsername() {
+ final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null) {
+ throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");
+ }
+ if (authentication.getPrincipal() instanceof UserDetails) {
+ UserDetails userDetails = (UserDetails) authentication.getPrincipal();
+ return userDetails.getUsername();
+ }
+ throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");
+ }
+
+ /**
+ * 获取系统用户ID
+ * @return 系统用户ID
+ */
+ public static Long getCurrentUserId() {
+ UserDetails userDetails = getCurrentUser();
+ return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class);
+ }
+
+ /**
+ * 获取当前用户的数据权限
+ * @return /
+ */
+ public static List getCurrentUserDataScope(){
+ UserDetails userDetails = getCurrentUser();
+ //log.error("-------------------");
+ String str_json=JSONUtil.toJsonStr(userDetails);
+ // log.error(str_json);
+ JSONObject obj=new JSONObject(str_json);
+ JSONArray array=obj.getJSONArray("dataScopes");
+ //JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes"));
+ //log.error(array.toString());
+ //log.error(array.size()+"");
+ 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/youchain-common/src/main/java/com/youchain/utils/SpringContextHolder.java b/youchain-common/src/main/java/com/youchain/utils/SpringContextHolder.java
new file mode 100644
index 0000000..ad883b8
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/SpringContextHolder.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Jie
+ * @date 2019-01-07
+ */
+@Slf4j
+public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
+
+ private static ApplicationContext applicationContext = null;
+ private static final List 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;
+ }
+
+ /**
+ * 获取 @Service 的所有 bean 名称
+ * @return /
+ */
+ public static List getAllServiceBeanName() {
+ return new ArrayList<>(Arrays.asList(applicationContext
+ .getBeanNamesForAnnotation(Service.class)));
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/StringUtils.java b/youchain-common/src/main/java/com/youchain/utils/StringUtils.java
new file mode 100644
index 0000000..93b9850
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils;
+
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+import com.youchain.config.ElAdminProperties;
+import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
+import net.dreamlu.mica.ip2region.core.IpInfo;
+import nl.basjes.parse.useragent.UserAgent;
+import nl.basjes.parse.useragent.UserAgentAnalyzer;
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+
+/**
+ * @author Liu Xue
+ * 字符串工具类, 继承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/youchain-common/src/main/java/com/youchain/utils/ThrowableUtil.java b/youchain-common/src/main/java/com/youchain/utils/ThrowableUtil.java
new file mode 100644
index 0000000..d75fe8a
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 异常工具 2019-01-06
+ * @author Liu Xue
+ */
+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/youchain-common/src/main/java/com/youchain/utils/TranslatorUtil.java b/youchain-common/src/main/java/com/youchain/utils/TranslatorUtil.java
new file mode 100644
index 0000000..5d75bff
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils;
+
+import cn.hutool.json.JSONArray;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+
+/**
+ * @author Liu Xue
+ * 翻译工具类
+ */
+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/youchain-common/src/main/java/com/youchain/utils/ValidationUtil.java b/youchain-common/src/main/java/com/youchain/utils/ValidationUtil.java
new file mode 100644
index 0000000..ebc423a
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/utils/ValidationUtil.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.youchain.utils;
+
+import cn.hutool.core.lang.Validator;
+import cn.hutool.core.util.ObjectUtil;
+import com.youchain.exception.BadRequestException;
+
+/**
+ * 验证工具
+ *
+ * @author Liu Xue
+ * @date 2018-11-23
+ */
+public class ValidationUtil {
+
+ /**
+ * 验证空
+ */
+ public static void isNull(Object obj, String entity, String parameter , Object value){
+ if(ObjectUtil.isNull(obj)){
+ String msg = entity + " 不存在: "+ parameter +" is "+ value;
+ throw new BadRequestException(msg);
+ }
+ }
+
+ /**
+ * 验证是否为邮箱
+ */
+ public static boolean isEmail(String email) {
+ return Validator.isEmail(email);
+ }
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/enums/CodeBiEnum.java b/youchain-common/src/main/java/com/youchain/utils/enums/CodeBiEnum.java
new file mode 100644
index 0000000..a03be38
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * 验证码业务场景
+ *
+ * @author Liu Xue
+ * @date 2020-05-02
+ */
+@Getter
+@AllArgsConstructor
+public enum CodeBiEnum {
+
+ /* 旧邮箱修改邮箱 */
+ ONE(1, "旧邮箱修改邮箱"),
+
+ /* 通过邮箱修改密码 */
+ TWO(2, "通过邮箱修改密码");
+
+ private final Integer code;
+ private final String description;
+
+ public static CodeBiEnum find(Integer code) {
+ for (CodeBiEnum value : CodeBiEnum.values()) {
+ if (value.getCode().equals(code)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/enums/CodeEnum.java b/youchain-common/src/main/java/com/youchain/utils/enums/CodeEnum.java
new file mode 100644
index 0000000..9d15e3c
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * 验证码业务场景对应的 Redis 中的 key
+ *
+ * @author Liu Xue
+ * @date 2020-05-02
+ */
+@Getter
+@AllArgsConstructor
+public enum CodeEnum {
+
+ /* 通过手机号码重置邮箱 */
+ PHONE_RESET_EMAIL_CODE("phone_reset_email_code_", "通过手机号码重置邮箱"),
+
+ /* 通过旧邮箱重置邮箱 */
+ EMAIL_RESET_EMAIL_CODE("email_reset_email_code_", "通过旧邮箱重置邮箱"),
+
+ /* 通过手机号码重置密码 */
+ PHONE_RESET_PWD_CODE("phone_reset_pwd_code_", "通过手机号码重置密码"),
+
+ /* 通过邮箱重置密码 */
+ EMAIL_RESET_PWD_CODE("email_reset_pwd_code_", "通过邮箱重置密码");
+
+ private final String key;
+ private final String description;
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/enums/DataScopeEnum.java b/youchain-common/src/main/java/com/youchain/utils/enums/DataScopeEnum.java
new file mode 100644
index 0000000..9488950
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ *
+ * 数据权限枚举
+ *
+ * @author Liu Xue
+ * @date 2020-05-07
+ */
+@Getter
+@AllArgsConstructor
+public enum DataScopeEnum {
+
+ /* 全部的数据权限 */
+ ALL("全部", "全部的数据权限"),
+
+ /* 自己部门的数据权限 */
+ THIS_LEVEL("本级", "自己部门的数据权限"),
+
+ /* 自定义的数据权限 */
+ CUSTOMIZE("自定义", "自定义的数据权限");
+
+ private final String value;
+ private final String description;
+
+ public static DataScopeEnum find(String val) {
+ for (DataScopeEnum dataScopeEnum : DataScopeEnum.values()) {
+ if (dataScopeEnum.getValue().equals(val)) {
+ return dataScopeEnum;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/youchain-common/src/main/java/com/youchain/utils/enums/RequestMethodEnum.java b/youchain-common/src/main/java/com/youchain/utils/enums/RequestMethodEnum.java
new file mode 100644
index 0000000..debfc5c
--- /dev/null
+++ b/youchain-common/src/main/java/com/youchain/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.youchain.utils.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author Liu Xue
+ * @website https://eladmin.vip
+ * @description
+ * @date 2020-06-10
+ **/
+@Getter
+@AllArgsConstructor
+public enum RequestMethodEnum {
+
+ /**
+ * 搜寻 @AnonymousGetMapping
+ */
+ GET("GET"),
+
+ /**
+ * 搜寻 @AnonymousPostMapping
+ */
+ POST("POST"),
+
+ /**
+ * 搜寻 @AnonymousPutMapping
+ */
+ PUT("PUT"),
+
+ /**
+ * 搜寻 @AnonymousPatchMapping
+ */
+ PATCH("PATCH"),
+
+ /**
+ * 搜寻 @AnonymousDeleteMapping
+ */
+ DELETE("DELETE"),
+
+ /**
+ * 否则就是所有 Request 接口都放行
+ */
+ ALL("All");
+
+ /**
+ * Request 类型
+ */
+ private final String type;
+
+ public static RequestMethodEnum find(String type) {
+ for (RequestMethodEnum value : RequestMethodEnum.values()) {
+ if (value.getType().equals(type)) {
+ return value;
+ }
+ }
+ return ALL;
+ }
+}
diff --git a/youchain-common/src/main/java/org/apache/poi/util/XMLHelper.java b/youchain-common/src/main/java/org/apache/poi/util/XMLHelper.java
new file mode 100644
index 0000000..8b2530a
--- /dev/null
+++ b/youchain-common/src/main/java/org/apache/poi/util/XMLHelper.java
@@ -0,0 +1,272 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.apache.poi.util;
+
+import java.io.StringReader;
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.validation.SchemaFactory;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+
+@Internal
+public final class XMLHelper {
+ static final String FEATURE_LOAD_DTD_GRAMMAR = "http://apache.org/xml/features/nonvalidating/load-dtd-grammar";
+ static final String FEATURE_LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+ static final String FEATURE_DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
+ static final String FEATURE_PARAMETER_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
+ static final String FEATURE_EXTERNAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
+ static final String PROPERTY_ENTITY_EXPANSION_LIMIT = "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit";
+ static final String PROPERTY_SECURITY_MANAGER = "http://apache.org/xml/properties/security-manager";
+ static final String METHOD_ENTITY_EXPANSION_XERCES = "setEntityExpansionLimit";
+ static final String[] SECURITY_MANAGERS = new String[]{"org.apache.xerces.util.SecurityManager"};
+ private static final Logger LOG = LogManager.getLogger(XMLHelper.class);
+ private static long lastLog;
+ private static final DocumentBuilderFactory documentBuilderFactory = getDocumentBuilderFactory();
+ private static final SAXParserFactory saxFactory = getSaxParserFactory();
+
+ private XMLHelper() {
+ }
+
+ public static DocumentBuilderFactory getDocumentBuilderFactory() {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setExpandEntityReferences(false);
+ factory.setValidating(false);
+ trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
+ trySet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalSchema", "");
+ trySet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalDTD", "");
+ trySet(factory::setFeature, "http://xml.org/sax/features/external-general-entities", false);
+ trySet(factory::setFeature, "http://xml.org/sax/features/external-parameter-entities", false);
+ trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
+ trySet(factory::setFeature, "http://apache.org/xml/features/disallow-doctype-decl", true);
+ trySet((n, b) -> {
+ factory.setXIncludeAware(b);
+ }, "XIncludeAware", false);
+ Object manager = getXercesSecurityManager();
+ if (manager == null || !trySet(factory::setAttribute, "http://apache.org/xml/properties/security-manager", manager)) {
+ trySet(factory::setAttribute, "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", 1);
+ }
+
+ return factory;
+ }
+
+ public static DocumentBuilder newDocumentBuilder() {
+ try {
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ documentBuilder.setEntityResolver(XMLHelper::ignoreEntity);
+ documentBuilder.setErrorHandler(new DocHelperErrorHandler());
+ return documentBuilder;
+ } catch (ParserConfigurationException var1) {
+ throw new IllegalStateException("cannot create a DocumentBuilder", var1);
+ }
+ }
+
+ public static SAXParserFactory getSaxParserFactory() {
+ try {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setValidating(false);
+ factory.setNamespaceAware(true);
+ trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
+ trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
+ trySet(factory::setFeature, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ trySet(factory::setFeature, "http://xml.org/sax/features/external-general-entities", false);
+ trySet(factory::setFeature, "http://apache.org/xml/features/disallow-doctype-decl", true);
+ return factory;
+ } catch (Error | RuntimeException var1) {
+ logThrowable(var1, "Failed to create SAXParserFactory", "-");
+ throw var1;
+ } catch (Exception var2) {
+ logThrowable(var2, "Failed to create SAXParserFactory", "-");
+ throw new RuntimeException("Failed to create SAXParserFactory", var2);
+ }
+ }
+
+ public static XMLReader newXMLReader() throws SAXException, ParserConfigurationException {
+ XMLReader xmlReader = saxFactory.newSAXParser().getXMLReader();
+ xmlReader.setEntityResolver(XMLHelper::ignoreEntity);
+ trySet(xmlReader::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
+ trySet(xmlReader::setFeature, "http://xml.org/sax/features/external-general-entities", false);
+ Object manager = getXercesSecurityManager();
+ if (manager == null || !trySet(xmlReader::setProperty, "http://apache.org/xml/properties/security-manager", manager)) {
+ trySet(xmlReader::setProperty, "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", 1);
+ }
+
+ return xmlReader;
+ }
+
+ public static XMLInputFactory newXMLInputFactory() {
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ trySet(factory::setProperty, "javax.xml.stream.isNamespaceAware", true);
+ trySet(factory::setProperty, "javax.xml.stream.isValidating", false);
+ trySet(factory::setProperty, "javax.xml.stream.supportDTD", false);
+ trySet(factory::setProperty, "javax.xml.stream.isSupportingExternalEntities", false);
+ return factory;
+ }
+
+ public static XMLOutputFactory newXMLOutputFactory() {
+ XMLOutputFactory factory = XMLOutputFactory.newInstance();
+ trySet(factory::setProperty, "javax.xml.stream.isRepairingNamespaces", true);
+ return factory;
+ }
+
+ public static XMLEventFactory newXMLEventFactory() {
+ return XMLEventFactory.newInstance();
+ }
+
+ public static TransformerFactory getTransformerFactory() {
+ TransformerFactory factory = TransformerFactory.newInstance();
+ trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
+ quietSet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalDTD", "");
+ trySet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", "");
+ quietSet(factory::setAttribute, "http://javax.xml.XMLConstants/property/accessExternalSchema", "");
+ return factory;
+ }
+
+ public static Transformer newTransformer() throws TransformerConfigurationException {
+ Transformer serializer = getTransformerFactory().newTransformer();
+ serializer.setOutputProperty("encoding", "UTF-8");
+ serializer.setOutputProperty("indent", "no");
+ serializer.setOutputProperty("method", "xml");
+ return serializer;
+ }
+
+ public static SchemaFactory getSchemaFactory() {
+ SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
+ trySet(factory::setFeature, "http://javax.xml.XMLConstants/feature/secure-processing", true);
+ trySet(factory::setProperty, "http://javax.xml.XMLConstants/property/accessExternalDTD", "");
+ trySet(factory::setProperty, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", "");
+ trySet(factory::setProperty, "http://javax.xml.XMLConstants/property/accessExternalSchema", "");
+ return factory;
+ }
+
+ private static Object getXercesSecurityManager() {
+ String[] var0 = SECURITY_MANAGERS;
+ int var1 = var0.length;
+
+ for(int var2 = 0; var2 < var1; ++var2) {
+ String securityManagerClassName = var0[var2];
+
+ try {
+ Object mgr = Class.forName(securityManagerClassName).getDeclaredConstructor().newInstance();
+ Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE);
+ setLimit.invoke(mgr, 1);
+ return mgr;
+ } catch (ClassNotFoundException var6) {
+ } catch (Throwable var7) {
+ logThrowable(var7, "SAX Feature unsupported", securityManagerClassName);
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean trySet(SecurityFeature feature, String name, boolean value) {
+ try {
+ feature.accept(name, value);
+ return true;
+ } catch (Exception var4) {
+ logThrowable(var4, "SAX Feature unsupported", name);
+ } catch (Error var5) {
+ logThrowable(var5, "Cannot set SAX feature because outdated XML parser in classpath", name);
+ }
+
+ return false;
+ }
+
+ private static boolean trySet(SecurityProperty property, String name, Object value) {
+ try {
+ property.accept(name, value);
+ return true;
+ } catch (Exception var4) {
+ logThrowable(var4, "SAX Feature unsupported", name);
+ } catch (Error var5) {
+ logThrowable(var5, "Cannot set SAX feature because outdated XML parser in classpath", name);
+ }
+
+ return false;
+ }
+
+ private static boolean quietSet(SecurityProperty property, String name, Object value) {
+ try {
+ property.accept(name, value);
+ return true;
+ } catch (Error | Exception var4) {
+ return false;
+ }
+ }
+
+ private static void logThrowable(Throwable t, String message, String name) {
+ if (System.currentTimeMillis() > lastLog + TimeUnit.MINUTES.toMillis(5L)) {
+ //LOG.atWarn().withThrowable(t).log("{} [log suppressed for 5 minutes]{}", message, name);
+ lastLog = System.currentTimeMillis();
+ }
+
+ }
+
+ private static InputSource ignoreEntity(String publicId, String systemId) {
+ return new InputSource(new StringReader(""));
+ }
+
+ private static class DocHelperErrorHandler implements ErrorHandler {
+ private DocHelperErrorHandler() {
+ }
+
+ public void warning(SAXParseException exception) {
+ this.printError(Level.WARN, exception);
+ }
+
+ public void error(SAXParseException exception) {
+ this.printError(Level.ERROR, exception);
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXException {
+ this.printError(Level.FATAL, exception);
+ throw exception;
+ }
+
+ private void printError(Level type, SAXParseException ex) {
+ String systemId = ex.getSystemId();
+ if (systemId != null) {
+ int index = systemId.lastIndexOf(47);
+ if (index != -1) {
+ systemId = systemId.substring(index + 1);
+ }
+ }
+
+ String message = (systemId == null ? "" : systemId) + ':' + ex.getLineNumber() + ':' + ex.getColumnNumber() + ':' + ex.getMessage();
+ XMLHelper.LOG.atLevel(type).withThrowable(ex).log(message);
+ }
+ }
+
+ @FunctionalInterface
+ private interface SecurityProperty {
+ void accept(String var1, Object var2) throws SAXException;
+ }
+
+ @FunctionalInterface
+ private interface SecurityFeature {
+ void accept(String var1, boolean var2) throws ParserConfigurationException, SAXException, TransformerException;
+ }
+}
diff --git a/youchain-common/src/main/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java b/youchain-common/src/main/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java
new file mode 100644
index 0000000..25d18f0
--- /dev/null
+++ b/youchain-common/src/main/java/org/apache/poi/xssf/streaming/SXSSFCreationHelper.java
@@ -0,0 +1,61 @@
+package org.apache.poi.xssf.streaming;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.poi.common.usermodel.HyperlinkType;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.ExtendedColor;
+import org.apache.poi.ss.usermodel.Hyperlink;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.util.Internal;
+import org.apache.poi.xssf.usermodel.XSSFCreationHelper;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+
+public class SXSSFCreationHelper implements CreationHelper {
+ private static final Logger LOG = LogManager.getLogger(SXSSFCreationHelper.class);
+ private final SXSSFWorkbook wb;
+ private final XSSFCreationHelper helper;
+
+ @Internal
+ public SXSSFCreationHelper(SXSSFWorkbook workbook) {
+ this.helper = new XSSFCreationHelper(workbook.getXSSFWorkbook());
+ this.wb = workbook;
+ }
+
+ public XSSFRichTextString createRichTextString(String text) {
+ // LOG.atInfo().log("SXSSF doesn't support Rich Text Strings, any formatting information will be lost");
+ return new XSSFRichTextString(text);
+ }
+
+ public SXSSFFormulaEvaluator createFormulaEvaluator() {
+ return new SXSSFFormulaEvaluator(this.wb);
+ }
+
+ public DataFormat createDataFormat() {
+ return this.helper.createDataFormat();
+ }
+
+ public Hyperlink createHyperlink(HyperlinkType type) {
+ return this.helper.createHyperlink(type);
+ }
+
+ public ExtendedColor createExtendedColor() {
+ return this.helper.createExtendedColor();
+ }
+
+ public ClientAnchor createClientAnchor() {
+ return this.helper.createClientAnchor();
+ }
+
+ public AreaReference createAreaReference(String reference) {
+ return new AreaReference(reference, this.wb.getSpreadsheetVersion());
+ }
+
+ public AreaReference createAreaReference(CellReference topLeft, CellReference bottomRight) {
+ return new AreaReference(topLeft, bottomRight, this.wb.getSpreadsheetVersion());
+ }
+}
+
diff --git a/youchain-common/src/test/java/com/youchain/utils/DateUtilsTest.java b/youchain-common/src/test/java/com/youchain/utils/DateUtilsTest.java
new file mode 100644
index 0000000..b60a0c9
--- /dev/null
+++ b/youchain-common/src/test/java/com/youchain/utils/DateUtilsTest.java
@@ -0,0 +1,26 @@
+package com.youchain.utils;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+public class DateUtilsTest {
+ @Test
+ public void test1() {
+ long l = System.currentTimeMillis() / 1000;
+ LocalDateTime localDateTime = DateUtil.fromTimeStamp(l);
+ System.out.print(DateUtil.localDateTimeFormatyMdHms(localDateTime));
+ }
+
+ @Test
+ public void test2() {
+ LocalDateTime now = LocalDateTime.now();
+ System.out.println(DateUtil.localDateTimeFormatyMdHms(now));
+ Date date = DateUtil.toDate(now);
+ LocalDateTime localDateTime = DateUtil.toLocalDateTime(date);
+ System.out.println(DateUtil.localDateTimeFormatyMdHms(localDateTime));
+ LocalDateTime localDateTime1 = DateUtil.fromTimeStamp(date.getTime() / 1000);
+ System.out.println(DateUtil.localDateTimeFormatyMdHms(localDateTime1));
+ }
+}
diff --git a/youchain-common/src/test/java/com/youchain/utils/EncryptUtilsTest.java b/youchain-common/src/test/java/com/youchain/utils/EncryptUtilsTest.java
new file mode 100644
index 0000000..36bae71
--- /dev/null
+++ b/youchain-common/src/test/java/com/youchain/utils/EncryptUtilsTest.java
@@ -0,0 +1,33 @@
+package com.youchain.utils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class EncryptUtilsTest {
+
+ /**
+ * 对称加密
+ */
+ @Test
+ public void testDesEncrypt() {
+ try {
+ Assertions.assertEquals("7772841DC6099402", EncryptUtils.desEncrypt("123456"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 对称解密
+ */
+ @Test
+ public void testDesDecrypt() {
+ try {
+ Assertions.assertEquals("123456", EncryptUtils.desDecrypt("7772841DC6099402"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/youchain-common/src/test/java/com/youchain/utils/FileUtilTest.java b/youchain-common/src/test/java/com/youchain/utils/FileUtilTest.java
new file mode 100644
index 0000000..d11bf17
--- /dev/null
+++ b/youchain-common/src/test/java/com/youchain/utils/FileUtilTest.java
@@ -0,0 +1,36 @@
+package com.youchain.utils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.mock.web.MockMultipartFile;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class FileUtilTest {
+
+ @Test
+ public void testToFile() {
+ long retval = FileUtil.toFile(new MockMultipartFile("foo", (byte[]) null)).getTotalSpace();
+ assertEquals(500695072768L, retval);
+ }
+
+ @Test
+ public void testGetExtensionName() {
+ Assertions.assertEquals("foo", FileUtil.getExtensionName("foo"));
+ Assertions.assertEquals("exe", FileUtil.getExtensionName("bar.exe"));
+ }
+
+ @Test
+ public void testGetFileNameNoEx() {
+ Assertions.assertEquals("foo", FileUtil.getFileNameNoEx("foo"));
+ Assertions.assertEquals("bar", FileUtil.getFileNameNoEx("bar.txt"));
+ }
+
+ @Test
+ public void testGetSize() {
+ Assertions.assertEquals("1000B ", FileUtil.getSize(1000));
+ Assertions.assertEquals("1.00KB ", FileUtil.getSize(1024));
+ Assertions.assertEquals("1.00MB ", FileUtil.getSize(1048576));
+ Assertions.assertEquals("1.00GB ", FileUtil.getSize(1073741824));
+ }
+}
diff --git a/youchain-common/src/test/java/com/youchain/utils/StringUtilsTest.java b/youchain-common/src/test/java/com/youchain/utils/StringUtilsTest.java
new file mode 100644
index 0000000..8569db3
--- /dev/null
+++ b/youchain-common/src/test/java/com/youchain/utils/StringUtilsTest.java
@@ -0,0 +1,44 @@
+package com.youchain.utils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class StringUtilsTest {
+
+ @Test
+ public void testToCamelCase() {
+ assertNull(StringUtils.toCamelCase(null));
+ }
+
+ @Test
+ public void testToCapitalizeCamelCase() {
+ assertNull(StringUtils.toCapitalizeCamelCase(null));
+ Assertions.assertEquals("HelloWorld", StringUtils.toCapitalizeCamelCase("hello_world"));
+ }
+
+ @Test
+ public void testToUnderScoreCase() {
+ assertNull(StringUtils.toUnderScoreCase(null));
+ Assertions.assertEquals("hello_world", StringUtils.toUnderScoreCase("helloWorld"));
+ Assertions.assertEquals("\u0000\u0000", StringUtils.toUnderScoreCase("\u0000\u0000"));
+ Assertions.assertEquals("\u0000_a", StringUtils.toUnderScoreCase("\u0000A"));
+ }
+
+ @Test
+ public void testGetWeekDay() {
+ SimpleDateFormat simpleDateformat = new SimpleDateFormat("E");
+ Assertions.assertEquals(simpleDateformat.format(new Date()), StringUtils.getWeekDay());
+ }
+
+ @Test
+ public void testGetIP() {
+ Assertions.assertEquals("127.0.0.1", StringUtils.getIp(new MockHttpServletRequest()));
+ }
+}
diff --git a/youchain-generator/pom.xml b/youchain-generator/pom.xml
new file mode 100644
index 0000000..c995405
--- /dev/null
+++ b/youchain-generator/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+ youchain
+ com.youchain
+ 2.6
+
+ 4.0.0
+
+ youchain-generator
+ 代码生成模块
+
+
+ 1.10
+
+
+
+
+ com.youchain
+ youchain-common
+ 2.6
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-freemarker
+
+
+
+
+ commons-configuration
+ commons-configuration
+ ${configuration.version}
+
+
+
\ No newline at end of file
diff --git a/youchain-generator/src/main/java/com/youchain/domain/ColumnInfo.java b/youchain-generator/src/main/java/com/youchain/domain/ColumnInfo.java
new file mode 100644
index 0000000..9133f68
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/domain/ColumnInfo.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.domain;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import com.youchain.utils.GenUtil;
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * 列的数据信息
+ * @author Liu Xue
+ * @date 2019-01-02
+ */
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+@Table(name = "code_column_config")
+public class ColumnInfo implements Serializable {
+
+ @Id
+ @Column(name = "column_id")
+ @ApiModelProperty(value = "ID", hidden = true)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @ApiModelProperty(value = "表名")
+ private String tableName;
+
+ @ApiModelProperty(value = "数据库字段名称")
+ private String columnName;
+
+ @ApiModelProperty(value = "数据库字段类型")
+ private String columnType;
+
+ @ApiModelProperty(value = "数据库字段键类型")
+ private String keyType;
+
+ @ApiModelProperty(value = "字段额外的参数")
+ private String extra;
+
+ @ApiModelProperty(value = "数据库字段描述")
+ private String remark;
+
+ @ApiModelProperty(value = "是否必填")
+ private Boolean notNull;
+
+ @ApiModelProperty(value = "是否在列表显示")
+ private Boolean listShow;
+
+ @ApiModelProperty(value = "是否表单显示")
+ private Boolean formShow;
+
+ @ApiModelProperty(value = "表单类型")
+ private String formType;
+
+ @ApiModelProperty(value = "查询 1:模糊 2:精确")
+ private String queryType;
+
+ @ApiModelProperty(value = "字典名称")
+ private String dictName;
+
+ @ApiModelProperty(value = "日期注解")
+ private String dateAnnotation;
+
+ public ColumnInfo(String tableName, String columnName, Boolean notNull, String columnType, String remark, String keyType, String extra) {
+ this.tableName = tableName;
+ this.columnName = columnName;
+ this.columnType = columnType;
+ this.keyType = keyType;
+ this.extra = extra;
+ this.notNull = notNull;
+ if(GenUtil.PK.equalsIgnoreCase(keyType) && GenUtil.EXTRA.equalsIgnoreCase(extra)){
+ this.notNull = false;
+ }
+ this.remark = remark;
+ this.listShow = true;
+ this.formShow = true;
+ }
+}
diff --git a/youchain-generator/src/main/java/com/youchain/domain/GenConfig.java b/youchain-generator/src/main/java/com/youchain/domain/GenConfig.java
new file mode 100644
index 0000000..b7cc80b
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/domain/GenConfig.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.domain;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import javax.persistence.*;
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/**
+ * 代码生成配置
+ * @author Liu Xue
+ * @date 2019-01-03
+ */
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+@Table(name = "code_gen_config")
+public class GenConfig implements Serializable {
+
+ public GenConfig(String tableName) {
+ this.tableName = tableName;
+ }
+
+ @Id
+ @Column(name = "config_id")
+ @ApiModelProperty(value = "ID", hidden = true)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @NotBlank
+ @ApiModelProperty(value = "表名")
+ private String tableName;
+
+ @ApiModelProperty(value = "接口名称")
+ private String apiAlias;
+
+ @NotBlank
+ @ApiModelProperty(value = "包路径")
+ private String pack;
+
+ @NotBlank
+ @ApiModelProperty(value = "模块名")
+ private String moduleName;
+
+ @NotBlank
+ @ApiModelProperty(value = "前端文件路径")
+ private String path;
+
+ @ApiModelProperty(value = "前端文件路径")
+ private String apiPath;
+
+ @ApiModelProperty(value = "作者")
+ private String author;
+
+ @ApiModelProperty(value = "表前缀")
+ private String prefix;
+
+ @ApiModelProperty(value = "是否覆盖")
+ private Boolean cover = false;
+}
diff --git a/youchain-generator/src/main/java/com/youchain/domain/vo/TableInfo.java b/youchain-generator/src/main/java/com/youchain/domain/vo/TableInfo.java
new file mode 100644
index 0000000..bc6d136
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/domain/vo/TableInfo.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 表的数据信息
+ * @author Liu Xue
+ * @date 2019-01-02
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class TableInfo {
+
+ /** 表名称 */
+ private Object tableName;
+
+ /** 创建日期 */
+ private Object createTime;
+
+ /** 数据库引擎 */
+ private Object engine;
+
+ /** 编码集 */
+ private Object coding;
+
+ /** 备注 */
+ private Object remark;
+
+
+}
diff --git a/youchain-generator/src/main/java/com/youchain/repository/ColumnInfoRepository.java b/youchain-generator/src/main/java/com/youchain/repository/ColumnInfoRepository.java
new file mode 100644
index 0000000..7137b8f
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/repository/ColumnInfoRepository.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.repository;
+
+import com.youchain.domain.ColumnInfo;
+import org.springframework.data.jpa.repository.JpaRepository;
+import java.util.List;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-14
+ */
+public interface ColumnInfoRepository extends JpaRepository {
+
+ /**
+ * 查询表信息
+ * @param tableName 表格名
+ * @return 表信息
+ */
+ List findByTableNameOrderByIdAsc(String tableName);
+}
diff --git a/youchain-generator/src/main/java/com/youchain/repository/GenConfigRepository.java b/youchain-generator/src/main/java/com/youchain/repository/GenConfigRepository.java
new file mode 100644
index 0000000..c36a301
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/repository/GenConfigRepository.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.youchain.repository;
+
+import com.youchain.domain.GenConfig;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-14
+ */
+public interface GenConfigRepository extends JpaRepository {
+
+ /**
+ * 查询表配置
+ * @param tableName 表名
+ * @return /
+ */
+ GenConfig findByTableName(String tableName);
+}
diff --git a/youchain-generator/src/main/java/com/youchain/rest/GenConfigController.java b/youchain-generator/src/main/java/com/youchain/rest/GenConfigController.java
new file mode 100644
index 0000000..6792906
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/rest/GenConfigController.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.youchain.rest;
+
+import com.youchain.domain.GenConfig;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import com.youchain.service.GenConfigService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-14
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/genConfig")
+@Api(tags = "系统:代码生成器配置管理")
+public class GenConfigController {
+
+ private final GenConfigService genConfigService;
+
+ @ApiOperation("查询")
+ @GetMapping(value = "/{tableName}")
+ public ResponseEntity queryGenConfig(@PathVariable String tableName){
+ return new ResponseEntity<>(genConfigService.find(tableName), HttpStatus.OK);
+ }
+
+ @PutMapping
+ @ApiOperation("修改")
+ public ResponseEntity updateGenConfig(@Validated @RequestBody GenConfig genConfig){
+ return new ResponseEntity<>(genConfigService.update(genConfig.getTableName(), genConfig),HttpStatus.OK);
+ }
+}
diff --git a/youchain-generator/src/main/java/com/youchain/rest/GeneratorController.java b/youchain-generator/src/main/java/com/youchain/rest/GeneratorController.java
new file mode 100644
index 0000000..0f025c6
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/rest/GeneratorController.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.rest;
+
+import com.youchain.exception.BadRequestException;
+import com.youchain.utils.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import com.youchain.domain.ColumnInfo;
+import com.youchain.service.GenConfigService;
+import com.youchain.service.GeneratorService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-02
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/generator")
+@Api(tags = "系统:代码生成管理")
+public class GeneratorController {
+
+ private final GeneratorService generatorService;
+ private final GenConfigService genConfigService;
+
+ @Value("${generator.enabled}")
+ private Boolean generatorEnabled;
+
+ @ApiOperation("查询数据库数据")
+ @GetMapping(value = "/tables/all")
+ public ResponseEntity queryAllTables(){
+ return new ResponseEntity<>(generatorService.getTables(), HttpStatus.OK);
+ }
+
+ @ApiOperation("查询数据库数据")
+ @GetMapping(value = "/tables")
+ public ResponseEntity queryTables(@RequestParam(defaultValue = "") String name,
+ @RequestParam(defaultValue = "0")Integer page,
+ @RequestParam(defaultValue = "10")Integer size){
+ int[] startEnd = PageUtil.transToStartEnd(page, size);
+ return new ResponseEntity<>(generatorService.getTables(name,startEnd), HttpStatus.OK);
+ }
+
+ @ApiOperation("查询字段数据")
+ @GetMapping(value = "/columns")
+ public ResponseEntity queryColumns(@RequestParam String tableName){
+ List columnInfos = generatorService.getColumns(tableName);
+ return new ResponseEntity<>(PageUtil.toPage(columnInfos,columnInfos.size()), HttpStatus.OK);
+ }
+
+ @ApiOperation("保存字段数据")
+ @PutMapping
+ public ResponseEntity saveColumn(@RequestBody List columnInfos){
+ generatorService.save(columnInfos);
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+
+ @ApiOperation("同步字段数据")
+ @PostMapping(value = "sync")
+ public ResponseEntity syncColumn(@RequestBody List tables){
+ for (String table : tables) {
+ generatorService.sync(generatorService.getColumns(table), generatorService.query(table));
+ }
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+
+ @ApiOperation("生成代码")
+ @PostMapping(value = "/{tableName}/{type}")
+ public ResponseEntity generatorCode(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response){
+ if(!generatorEnabled && type == 0){
+ throw new BadRequestException("此环境不允许生成代码,请选择预览或者下载查看!");
+ }
+ switch (type){
+ // 生成代码
+ case 0: generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName));
+ break;
+ // 预览
+ case 1: return generatorService.preview(genConfigService.find(tableName), generatorService.getColumns(tableName));
+ // 打包
+ case 2: generatorService.download(genConfigService.find(tableName), generatorService.getColumns(tableName), request, response);
+ break;
+ default: throw new BadRequestException("没有这个选项");
+ }
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+}
diff --git a/youchain-generator/src/main/java/com/youchain/service/GenConfigService.java b/youchain-generator/src/main/java/com/youchain/service/GenConfigService.java
new file mode 100644
index 0000000..46663e6
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/service/GenConfigService.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.youchain.service;
+
+import com.youchain.domain.GenConfig;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-14
+ */
+public interface GenConfigService {
+
+ /**
+ * 查询表配置
+ * @param tableName 表名
+ * @return 表配置
+ */
+ GenConfig find(String tableName);
+
+ /**
+ * 更新表配置
+ * @param tableName 表名
+ * @param genConfig 表配置
+ * @return 表配置
+ */
+ GenConfig update(String tableName, GenConfig genConfig);
+}
diff --git a/youchain-generator/src/main/java/com/youchain/service/GeneratorService.java b/youchain-generator/src/main/java/com/youchain/service/GeneratorService.java
new file mode 100644
index 0000000..c94585b
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/service/GeneratorService.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.service;
+
+import com.youchain.domain.ColumnInfo;
+import com.youchain.domain.GenConfig;
+import org.springframework.http.ResponseEntity;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-02
+ */
+public interface GeneratorService {
+
+ /**
+ * 查询数据库元数据
+ * @param name 表名
+ * @param startEnd 分页参数
+ * @return /
+ */
+ Object getTables(String name, int[] startEnd);
+
+ /**
+ * 得到数据表的元数据
+ * @param name 表名
+ * @return /
+ */
+ List getColumns(String name);
+
+ /**
+ * 同步表数据
+ * @param columnInfos /
+ * @param columnInfoList /
+ */
+ void sync(List columnInfos, List columnInfoList);
+
+ /**
+ * 保持数据
+ * @param columnInfos /
+ */
+ void save(List columnInfos);
+
+ /**
+ * 获取所有table
+ * @return /
+ */
+ Object getTables();
+
+ /**
+ * 代码生成
+ * @param genConfig 配置信息
+ * @param columns 字段信息
+ */
+ void generator(GenConfig genConfig, List columns);
+
+ /**
+ * 预览
+ * @param genConfig 配置信息
+ * @param columns 字段信息
+ * @return /
+ */
+ ResponseEntity preview(GenConfig genConfig, List columns);
+
+ /**
+ * 打包下载
+ * @param genConfig 配置信息
+ * @param columns 字段信息
+ * @param request /
+ * @param response /
+ */
+ void download(GenConfig genConfig, List columns, HttpServletRequest request, HttpServletResponse response);
+
+ /**
+ * 查询数据库的表字段数据数据
+ * @param table /
+ * @return /
+ */
+ List query(String table);
+}
diff --git a/youchain-generator/src/main/java/com/youchain/service/impl/GenConfigServiceImpl.java b/youchain-generator/src/main/java/com/youchain/service/impl/GenConfigServiceImpl.java
new file mode 100644
index 0000000..3a7a614
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/service/impl/GenConfigServiceImpl.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.youchain.service.impl;
+
+import com.youchain.domain.GenConfig;
+import com.youchain.repository.GenConfigRepository;
+import com.youchain.service.GenConfigService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import java.io.File;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-14
+ */
+@Service
+@RequiredArgsConstructor
+public class GenConfigServiceImpl implements GenConfigService {
+
+ private final GenConfigRepository genConfigRepository;
+
+ @Override
+ public GenConfig find(String tableName) {
+ GenConfig genConfig = genConfigRepository.findByTableName(tableName);
+ if(genConfig == null){
+ return new GenConfig(tableName);
+ }
+ return genConfig;
+ }
+
+ @Override
+ public GenConfig update(String tableName, GenConfig genConfig) {
+ String separator = File.separator;
+ String[] paths;
+ String symbol = "\\";
+ if (symbol.equals(separator)) {
+ paths = genConfig.getPath().split("\\\\");
+ } else {
+ paths = genConfig.getPath().split(File.separator);
+ }
+ StringBuilder api = new StringBuilder();
+ for (String path : paths) {
+ api.append(path);
+ api.append(separator);
+ if ("src".equals(path)) {
+ api.append("api");
+ break;
+ }
+ }
+ genConfig.setApiPath(api.toString());
+ return genConfigRepository.save(genConfig);
+ }
+}
diff --git a/youchain-generator/src/main/java/com/youchain/service/impl/GeneratorServiceImpl.java b/youchain-generator/src/main/java/com/youchain/service/impl/GeneratorServiceImpl.java
new file mode 100644
index 0000000..1889a4b
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/service/impl/GeneratorServiceImpl.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ZipUtil;
+import com.youchain.domain.ColumnInfo;
+import com.youchain.domain.GenConfig;
+import com.youchain.domain.vo.TableInfo;
+import com.youchain.exception.BadRequestException;
+import com.youchain.repository.ColumnInfoRepository;
+import com.youchain.service.GeneratorService;
+import com.youchain.utils.FileUtil;
+import com.youchain.utils.GenUtil;
+import com.youchain.utils.PageUtil;
+import com.youchain.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author Liu Xue
+ * @date 2019-01-02
+ */
+@Service
+@RequiredArgsConstructor
+public class GeneratorServiceImpl implements GeneratorService {
+ private static final Logger log = LoggerFactory.getLogger(GeneratorServiceImpl.class);
+ @PersistenceContext
+ private EntityManager em;
+
+ private final ColumnInfoRepository columnInfoRepository;
+
+ private final String CONFIG_MESSAGE = "请先配置生成器";
+ @Override
+ public Object getTables() {
+ // 使用预编译防止sql注入
+ String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " +
+ "where table_schema = (select database()) " +
+ "order by create_time desc";
+ Query query = em.createNativeQuery(sql);
+ return query.getResultList();
+ }
+
+ @Override
+ public Object getTables(String name, int[] startEnd) {
+ // 使用预编译防止sql注入
+ String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " +
+ "where table_schema = (select database()) " +
+ "and table_name like :table order by create_time desc";
+ Query query = em.createNativeQuery(sql);
+ query.setFirstResult(startEnd[0]);
+ query.setMaxResults(startEnd[1] - startEnd[0]);
+ query.setParameter("table", StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
+ List result = query.getResultList();
+ List tableInfos = new ArrayList<>();
+ for (Object obj : result) {
+ Object[] arr = (Object[]) obj;
+ tableInfos.add(new TableInfo(arr[0], arr[1], arr[2], arr[3], ObjectUtil.isNotEmpty(arr[4]) ? arr[4] : "-"));
+ }
+ String countSql = "select count(1) from information_schema.tables " +
+ "where table_schema = (select database()) and table_name like :table";
+ Query queryCount = em.createNativeQuery(countSql);
+ queryCount.setParameter("table", StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
+ Object totalElements = queryCount.getSingleResult();
+ return PageUtil.toPage(tableInfos, totalElements);
+ }
+
+ @Override
+ public List getColumns(String tableName) {
+ List columnInfos = columnInfoRepository.findByTableNameOrderByIdAsc(tableName);
+ if (CollectionUtil.isNotEmpty(columnInfos)) {
+ return columnInfos;
+ } else {
+ columnInfos = query(tableName);
+ return columnInfoRepository.saveAll(columnInfos);
+ }
+ }
+
+ @Override
+ public List query(String tableName) {
+ // 使用预编译防止sql注入
+ String sql = "select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns " +
+ "where table_name = ? and table_schema = (select database()) order by ordinal_position";
+ Query query = em.createNativeQuery(sql);
+ query.setParameter(1, tableName);
+ List result = query.getResultList();
+ List columnInfos = new ArrayList<>();
+ for (Object obj : result) {
+ Object[] arr = (Object[]) obj;
+ columnInfos.add(
+ new ColumnInfo(
+ tableName,
+ arr[0].toString(),
+ "NO".equals(arr[1]),
+ arr[2].toString(),
+ ObjectUtil.isNotNull(arr[3]) ? arr[3].toString() : null,
+ ObjectUtil.isNotNull(arr[4]) ? arr[4].toString() : null,
+ ObjectUtil.isNotNull(arr[5]) ? arr[5].toString() : null)
+ );
+ }
+ return columnInfos;
+ }
+
+ @Override
+ public void sync(List columnInfos, List columnInfoList) {
+ // 第一种情况,数据库类字段改变或者新增字段
+ for (ColumnInfo columnInfo : columnInfoList) {
+ // 根据字段名称查找
+ List columns = columnInfos.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
+ // 如果能找到,就修改部分可能被字段
+ if (CollectionUtil.isNotEmpty(columns)) {
+ ColumnInfo column = columns.get(0);
+ column.setColumnType(columnInfo.getColumnType());
+ column.setExtra(columnInfo.getExtra());
+ column.setKeyType(columnInfo.getKeyType());
+ if (StringUtils.isBlank(column.getRemark())) {
+ column.setRemark(columnInfo.getRemark());
+ }
+ columnInfoRepository.save(column);
+ } else {
+ // 如果找不到,则保存新字段信息
+ columnInfoRepository.save(columnInfo);
+ }
+ }
+ // 第二种情况,数据库字段删除了
+ for (ColumnInfo columnInfo : columnInfos) {
+ // 根据字段名称查找
+ List columns = columnInfoList.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
+ // 如果找不到,就代表字段被删除了,则需要删除该字段
+ if (CollectionUtil.isEmpty(columns)) {
+ columnInfoRepository.delete(columnInfo);
+ }
+ }
+ }
+
+ @Override
+ public void save(List columnInfos) {
+ columnInfoRepository.saveAll(columnInfos);
+ }
+
+ @Override
+ public void generator(GenConfig genConfig, List columns) {
+ if (genConfig.getId() == null) {
+ throw new BadRequestException(CONFIG_MESSAGE);
+ }
+ try {
+ GenUtil.generatorCode(columns, genConfig);
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ throw new BadRequestException("生成失败,请手动处理已生成的文件");
+ }
+ }
+
+ @Override
+ public ResponseEntity preview(GenConfig genConfig, List columns) {
+ if (genConfig.getId() == null) {
+ throw new BadRequestException(CONFIG_MESSAGE);
+ }
+ List> genList = GenUtil.preview(columns, genConfig);
+ return new ResponseEntity<>(genList, HttpStatus.OK);
+ }
+
+ @Override
+ public void download(GenConfig genConfig, List columns, HttpServletRequest request, HttpServletResponse response) {
+ if (genConfig.getId() == null) {
+ throw new BadRequestException(CONFIG_MESSAGE);
+ }
+ try {
+ File file = new File(GenUtil.download(columns, genConfig));
+ String zipPath = file.getPath() + ".zip";
+ ZipUtil.zip(file.getPath(), zipPath);
+ FileUtil.downloadFile(request, response, new File(zipPath), true);
+ } catch (IOException e) {
+ throw new BadRequestException("打包失败");
+ }
+ }
+}
diff --git a/youchain-generator/src/main/java/com/youchain/utils/ColUtil.java b/youchain-generator/src/main/java/com/youchain/utils/ColUtil.java
new file mode 100644
index 0000000..778fc2e
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/utils/ColUtil.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.utils;
+
+import org.apache.commons.configuration.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * sql字段转java
+ *
+ * @author Liu Xue
+ * @date 2019-01-03
+ */
+public class ColUtil {
+ private static final Logger log = LoggerFactory.getLogger(ColUtil.class);
+
+ /**
+ * 转换mysql数据类型为java数据类型
+ *
+ * @param type 数据库字段类型
+ * @return String
+ */
+ static String cloToJava(String type) {
+ Configuration config = getConfig();
+ assert config != null;
+ return config.getString(type, "unknowType");
+ }
+
+ /**
+ * 获取配置信息
+ */
+ public static PropertiesConfiguration getConfig() {
+ try {
+ return new PropertiesConfiguration("generator.properties");
+ } catch (ConfigurationException e) {
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+}
diff --git a/youchain-generator/src/main/java/com/youchain/utils/GenUtil.java b/youchain-generator/src/main/java/com/youchain/utils/GenUtil.java
new file mode 100644
index 0000000..83d2e5c
--- /dev/null
+++ b/youchain-generator/src/main/java/com/youchain/utils/GenUtil.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.utils;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.template.*;
+import com.youchain.domain.ColumnInfo;
+import com.youchain.domain.GenConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.ObjectUtils;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.time.LocalDate;
+import java.util.*;
+
+/**
+ * 代码生成
+ *
+ * @author Liu Xue
+ * @date 2019-01-02
+ */
+@Slf4j
+@SuppressWarnings({"unchecked", "all"})
+public class GenUtil {
+
+ private static final String TIMESTAMP = "Timestamp";
+
+ private static final String BIGDECIMAL = "BigDecimal";
+
+ public static final String PK = "PRI";
+
+ public static final String EXTRA = "auto_increment";
+
+ /**
+ * 获取后端代码模板名称
+ *
+ * @return List
+ */
+ private static List getAdminTemplateNames() {
+ List templateNames = new ArrayList<>();
+ templateNames.add("Entity");
+ templateNames.add("Dto");
+ templateNames.add("Mapper");
+ templateNames.add("Controller");
+ templateNames.add("QueryCriteria");
+ templateNames.add("Service");
+ templateNames.add("ServiceImpl");
+ templateNames.add("Repository");
+ return templateNames;
+ }
+
+ /**
+ * 获取前端代码模板名称
+ *
+ * @return List
+ */
+ private static List getFrontTemplateNames() {
+ List templateNames = new ArrayList<>();
+ templateNames.add("index");
+ templateNames.add("api");
+ return templateNames;
+ }
+
+ public static List> preview(List columns, GenConfig genConfig) {
+ Map genMap = getGenMap(columns, genConfig);
+ List> genList = new ArrayList<>();
+ // 获取后端模版
+ List templates = getAdminTemplateNames();
+ TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
+ for (String templateName : templates) {
+ Map map = new HashMap<>(1);
+ Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
+ map.put("content", template.render(genMap));
+ map.put("name", templateName);
+ genList.add(map);
+ }
+ // 获取前端模版
+ templates = getFrontTemplateNames();
+ for (String templateName : templates) {
+ Map map = new HashMap<>(1);
+ Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
+ map.put(templateName, template.render(genMap));
+ map.put("content", template.render(genMap));
+ map.put("name", templateName);
+ genList.add(map);
+ }
+ return genList;
+ }
+
+ public static String download(List columns, GenConfig genConfig) throws IOException {
+ // 拼接的路径:/tmpeladmin-gen-temp/,这个路径在Linux下需要root用户才有权限创建,非root用户会权限错误而失败,更改为: /tmp/eladmin-gen-temp/
+ // String tempPath =SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator;
+ String tempPath = FileUtil.SYS_TEM_DIR + "eladmin-gen-temp" + File.separator + genConfig.getTableName() + File.separator;
+ Map genMap = getGenMap(columns, genConfig);
+ TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
+ // 生成后端代码
+ List templates = getAdminTemplateNames();
+ for (String templateName : templates) {
+ Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
+ String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), tempPath + "eladmin" + File.separator);
+ assert filePath != null;
+ File file = new File(filePath);
+ // 如果非覆盖生成
+ if (!genConfig.getCover() && FileUtil.exist(file)) {
+ continue;
+ }
+ // 生成代码
+ genFile(file, template, genMap);
+ }
+ // 生成前端代码
+ templates = getFrontTemplateNames();
+ for (String templateName : templates) {
+ Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
+ String path = tempPath + "eladmin-web" + File.separator;
+ String apiPath = path + "src" + File.separator + "api" + File.separator;
+ String srcPath = path + "src" + File.separator + "views" + File.separator + genMap.get("changeClassName").toString() + File.separator;
+ String filePath = getFrontFilePath(templateName, apiPath, srcPath, genMap.get("changeClassName").toString());
+ assert filePath != null;
+ File file = new File(filePath);
+ // 如果非覆盖生成
+ if (!genConfig.getCover() && FileUtil.exist(file)) {
+ continue;
+ }
+ // 生成代码
+ genFile(file, template, genMap);
+ }
+ return tempPath;
+ }
+
+ public static void generatorCode(List columnInfos, GenConfig genConfig) throws IOException {
+ Map genMap = getGenMap(columnInfos, genConfig);
+ TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
+ // 生成后端代码
+ List templates = getAdminTemplateNames();
+ for (String templateName : templates) {
+ Template template = engine.getTemplate("generator/admin/" + templateName + ".ftl");
+ String rootPath = System.getProperty("user.dir");
+ String filePath = getAdminFilePath(templateName, genConfig, genMap.get("className").toString(), rootPath);
+
+ assert filePath != null;
+ File file = new File(filePath);
+
+ // 如果非覆盖生成
+ if (!genConfig.getCover() && FileUtil.exist(file)) {
+ continue;
+ }
+ // 生成代码
+ genFile(file, template, genMap);
+ }
+
+ // 生成前端代码
+ templates = getFrontTemplateNames();
+ for (String templateName : templates) {
+ Template template = engine.getTemplate("generator/front/" + templateName + ".ftl");
+ String filePath = getFrontFilePath(templateName, genConfig.getApiPath(), genConfig.getPath(), genMap.get("changeClassName").toString());
+
+ assert filePath != null;
+ File file = new File(filePath);
+
+ // 如果非覆盖生成
+ if (!genConfig.getCover() && FileUtil.exist(file)) {
+ continue;
+ }
+ // 生成代码
+ genFile(file, template, genMap);
+ }
+ }
+
+ // 获取模版数据
+ private static Map getGenMap(List columnInfos, GenConfig genConfig) {
+ // 存储模版字段数据
+ Map genMap = new HashMap<>(16);
+ // 接口别名
+ genMap.put("apiAlias", genConfig.getApiAlias());
+ // 包名称
+ genMap.put("package", genConfig.getPack());
+ // 模块名称
+ genMap.put("moduleName", genConfig.getModuleName());
+ // 作者
+ genMap.put("author", genConfig.getAuthor());
+ // 创建日期
+ genMap.put("date", LocalDate.now().toString());
+ // 表名
+ genMap.put("tableName", genConfig.getTableName());
+ // 大写开头的类名
+ String className = StringUtils.toCapitalizeCamelCase(genConfig.getTableName());
+ // 小写开头的类名
+ String changeClassName = StringUtils.toCamelCase(genConfig.getTableName());
+ // 判断是否去除表前缀
+ if (StringUtils.isNotEmpty(genConfig.getPrefix())) {
+ className = StringUtils.toCapitalizeCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix()));
+ changeClassName = StringUtils.toCamelCase(StrUtil.removePrefix(genConfig.getTableName(), genConfig.getPrefix()));
+ changeClassName = StringUtils.uncapitalize(changeClassName);
+ }
+ // 保存类名
+ genMap.put("className", className);
+ // 保存小写开头的类名
+ genMap.put("changeClassName", changeClassName);
+ // 存在 Timestamp 字段
+ genMap.put("hasTimestamp", false);
+ // 查询类中存在 Timestamp 字段
+ genMap.put("queryHasTimestamp", false);
+ // 存在 BigDecimal 字段
+ genMap.put("hasBigDecimal", false);
+ // 查询类中存在 BigDecimal 字段
+ genMap.put("queryHasBigDecimal", false);
+ // 是否需要创建查询
+ genMap.put("hasQuery", false);
+ // 自增主键
+ genMap.put("auto", false);
+ // 存在字典
+ genMap.put("hasDict", false);
+ // 存在日期注解
+ genMap.put("hasDateAnnotation", false);
+ // 保存字段信息
+ List> columns = new ArrayList<>();
+ // 保存查询字段的信息
+ List> queryColumns = new ArrayList<>();
+ // 存储字典信息
+ List dicts = new ArrayList<>();
+ // 存储 between 信息
+ List> betweens = new ArrayList<>();
+ // 存储不为空的字段信息
+ List> isNotNullColumns = new ArrayList<>();
+
+ for (ColumnInfo column : columnInfos) {
+ Map listMap = new HashMap<>(16);
+ // 字段描述
+ listMap.put("remark", column.getRemark());
+ // 字段类型
+ listMap.put("columnKey", column.getKeyType());
+ // 主键类型
+ String colType = ColUtil.cloToJava(column.getColumnType());
+ // 小写开头的字段名
+ String changeColumnName = StringUtils.toCamelCase(column.getColumnName());
+ // 大写开头的字段名
+ String capitalColumnName = StringUtils.toCapitalizeCamelCase(column.getColumnName());
+ if (PK.equals(column.getKeyType())) {
+ // 存储主键类型
+ genMap.put("pkColumnType", colType);
+ // 存储小写开头的字段名
+ genMap.put("pkChangeColName", changeColumnName);
+ // 存储大写开头的字段名
+ genMap.put("pkCapitalColName", capitalColumnName);
+ }
+ // 是否存在 Timestamp 类型的字段
+ if (TIMESTAMP.equals(colType)) {
+ genMap.put("hasTimestamp", true);
+ }
+ // 是否存在 BigDecimal 类型的字段
+ if (BIGDECIMAL.equals(colType)) {
+ genMap.put("hasBigDecimal", true);
+ }
+ // 主键是否自增
+ if (EXTRA.equals(column.getExtra())) {
+ genMap.put("auto", true);
+ }
+ // 主键存在字典
+ if (StringUtils.isNotBlank(column.getDictName())) {
+ genMap.put("hasDict", true);
+ if(!dicts.contains(column.getDictName()))
+ dicts.add(column.getDictName());
+ }
+
+ // 存储字段类型
+ listMap.put("columnType", colType);
+ // 存储字原始段名称
+ listMap.put("columnName", column.getColumnName());
+ // 不为空
+ listMap.put("istNotNull", column.getNotNull());
+ // 字段列表显示
+ listMap.put("columnShow", column.getListShow());
+ // 表单显示
+ listMap.put("formShow", column.getFormShow());
+ // 表单组件类型
+ listMap.put("formType", StringUtils.isNotBlank(column.getFormType()) ? column.getFormType() : "Input");
+ // 小写开头的字段名称
+ listMap.put("changeColumnName", changeColumnName);
+ //大写开头的字段名称
+ listMap.put("capitalColumnName", capitalColumnName);
+ // 字典名称
+ listMap.put("dictName", column.getDictName());
+ // 日期注解
+ listMap.put("dateAnnotation", column.getDateAnnotation());
+ if (StringUtils.isNotBlank(column.getDateAnnotation())) {
+ genMap.put("hasDateAnnotation", true);
+ }
+ // 添加非空字段信息
+ if (column.getNotNull()) {
+ isNotNullColumns.add(listMap);
+ }
+ // 判断是否有查询,如有则把查询的字段set进columnQuery
+ if (!StringUtils.isBlank(column.getQueryType())) {
+ // 查询类型
+ listMap.put("queryType", column.getQueryType());
+ // 是否存在查询
+ genMap.put("hasQuery", true);
+ if (TIMESTAMP.equals(colType)) {
+ // 查询中存储 Timestamp 类型
+ genMap.put("queryHasTimestamp", true);
+ }
+ if (BIGDECIMAL.equals(colType)) {
+ // 查询中存储 BigDecimal 类型
+ genMap.put("queryHasBigDecimal", true);
+ }
+ if ("between".equalsIgnoreCase(column.getQueryType())) {
+ betweens.add(listMap);
+ } else {
+ // 添加到查询列表中
+ queryColumns.add(listMap);
+ }
+ }
+ // 添加到字段列表中
+ columns.add(listMap);
+ }
+ // 保存字段列表
+ genMap.put("columns", columns);
+ // 保存查询列表
+ genMap.put("queryColumns", queryColumns);
+ // 保存字段列表
+ genMap.put("dicts", dicts);
+ // 保存查询列表
+ genMap.put("betweens", betweens);
+ // 保存非空字段信息
+ genMap.put("isNotNullColumns", isNotNullColumns);
+ return genMap;
+ }
+
+ /**
+ * 定义后端文件路径以及名称
+ */
+ private static String getAdminFilePath(String templateName, GenConfig genConfig, String className, String rootPath) {
+ String projectPath = rootPath + File.separator + genConfig.getModuleName();
+ String packagePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
+ if (!ObjectUtils.isEmpty(genConfig.getPack())) {
+ packagePath += genConfig.getPack().replace(".", File.separator) + File.separator;
+ }
+
+ if ("Entity".equals(templateName)) {
+ return packagePath + "domain" + File.separator + className + ".java";
+ }
+
+ if ("Controller".equals(templateName)) {
+ return packagePath + "rest" + File.separator + className + "Controller.java";
+ }
+
+ if ("Service".equals(templateName)) {
+ return packagePath + "service" + File.separator + className + "Service.java";
+ }
+
+ if ("ServiceImpl".equals(templateName)) {
+ return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
+ }
+
+ if ("Dto".equals(templateName)) {
+ return packagePath + "service" + File.separator + "dto" + File.separator + className + "Dto.java";
+ }
+
+ if ("QueryCriteria".equals(templateName)) {
+ return packagePath + "service" + File.separator + "dto" + File.separator + className + "QueryCriteria.java";
+ }
+
+ if ("Mapper".equals(templateName)) {
+ return packagePath + "service" + File.separator + "mapstruct" + File.separator + className + "Mapper.java";
+ }
+
+ if ("Repository".equals(templateName)) {
+ return packagePath + "repository" + File.separator + className + "Repository.java";
+ }
+
+ return null;
+ }
+
+ /**
+ * 定义前端文件路径以及名称
+ */
+ private static String getFrontFilePath(String templateName, String apiPath, String path, String apiName) {
+
+ if ("api".equals(templateName)) {
+ return apiPath + File.separator + apiName + ".js";
+ }
+
+ if ("index".equals(templateName)) {
+ return path + File.separator + "index.vue";
+ }
+
+ return null;
+ }
+
+ private static void genFile(File file, Template template, Map map) throws IOException {
+ // 生成目标文件
+ Writer writer = null;
+ try {
+ FileUtil.touch(file);
+ writer = new FileWriter(file);
+ template.render(map, writer);
+ } catch (TemplateException | IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ assert writer != null;
+ writer.close();
+ }
+ }
+}
diff --git a/youchain-logging/pom.xml b/youchain-logging/pom.xml
new file mode 100644
index 0000000..e0e2bc5
--- /dev/null
+++ b/youchain-logging/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ youchain
+ com.youchain
+ 2.6
+
+ 4.0.0
+
+ youchain-logging
+ 日志模块
+
+
+
+ com.youchain
+ youchain-common
+ 2.6
+
+
+
\ No newline at end of file
diff --git a/youchain-logging/src/main/java/com/youchain/annotation/Log.java b/youchain-logging/src/main/java/com/youchain/annotation/Log.java
new file mode 100644
index 0000000..2484354
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/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.youchain.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-24
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Log {
+ String value() default "";
+}
diff --git a/youchain-logging/src/main/java/com/youchain/aspect/LogAspect.java b/youchain-logging/src/main/java/com/youchain/aspect/LogAspect.java
new file mode 100644
index 0000000..dd8db45
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/aspect/LogAspect.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.aspect;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.youchain.utils.RequestHolder;
+import com.youchain.utils.SecurityUtils;
+import com.youchain.utils.StringUtils;
+import com.youchain.utils.ThrowableUtil;
+import lombok.extern.slf4j.Slf4j;
+import com.youchain.domain.Log;
+import com.youchain.service.LogService;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.springframework.security.web.context.HttpRequestResponseHolder;
+import org.springframework.stereotype.Component;
+import javax.servlet.http.HttpServletRequest;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * @author Liu Xue
+ * @date 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.youchain.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();
+ String result_data = handlerResult(result);
+ //log.error("----结束了---"+result_data);
+ Log log_data = new Log("INFO",System.currentTimeMillis() - currentTime.get());
+ currentTime.remove();
+ HttpServletRequest request = RequestHolder.getHttpServletRequest();
+ String url=handlerUrl(request);
+ String parm=handleParm(request);
+ if(parm!=null&&parm.length()>0){
+ url=url+"?"+parm;
+ }
+
+ logService.save(url,result_data,getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log_data);
+
+ return result;
+ }
+
+ private String handleParm( HttpServletRequest request) {
+ if (request == null) {
+ return "request为空";
+ }
+ String parm="";
+ try {
+ parm=request.getQueryString();
+ } catch (Exception e) {
+ parm="parm获取失败";
+ log.error("parm获取失败", e);
+ }
+ return parm;
+ }
+
+ private String handlerUrl( HttpServletRequest request) {
+ if (request == null) {
+ return "request为空";
+ }
+ String url="";
+ try {
+ url=request.getRequestURL().toString();
+ } catch (Exception e) {
+ url="url获取失败";
+ log.error("url获取失败", e);
+ }
+ return url;
+ }
+
+
+ private String handlerResult(Object result) {
+ if (result == null) {
+ return null;
+ }
+ String resultStr;
+ try {
+ if (result instanceof String) {
+ resultStr = (String) result;
+ } else {
+ resultStr = JSONUtil.toJsonStr(result);// 如果返回结果非String类型,转换成JSON格式的字符串
+ }
+
+ if (resultStr.length() > 10000) {
+ resultStr = resultStr.substring(0, 10000);
+ }
+ } catch (Exception e) {
+ resultStr = result.toString();
+ log.error("接口出入参日志打印切面处理返回参数异常", e);
+ }
+ return resultStr;
+ }
+
+ @AfterReturning(returning = "returnValue", pointcut = "logPointcut()")
+ public void doAfterReturning(JoinPoint joinPoint,Object returnValue) throws Throwable {
+ // 处理完请求,返回内容
+ /* log.info("类名:"+joinPoint.getSignature().getDeclaringTypeName()+
+ "、方法名: "+joinPoint.getSignature().getName()+"()、====>@Before:请求参数为:{}", Arrays.toString(joinPoint.getArgs()));
+*/
+ }
+
+
+
+ /**
+ * 配置异常通知
+ *
+ * @param joinPoint join point for advice
+ * @param e exception
+ */
+ @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
+ public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
+ String errDetail=ThrowableUtil.getStackTrace(e)+"";
+ log.error("拦截到异常消息", errDetail);
+ Log log_data = new Log("ERROR",System.currentTimeMillis() - currentTime.get());
+ currentTime.remove();
+
+ log_data.setExceptionDetail(errDetail);
+ HttpServletRequest request = RequestHolder.getHttpServletRequest();
+
+ String url=handlerUrl(request);
+ String parm=handleParm(request);
+ if(parm!=null&&parm.length()>0){
+ url=url+"?"+parm;
+ }
+ logService.save(url,"",getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log_data);
+ }
+
+ public String getUsername() {
+ try {
+ return SecurityUtils.getCurrentUsername();
+ }catch (Exception e){
+ return "";
+ }
+ }
+}
diff --git a/youchain-logging/src/main/java/com/youchain/domain/Log.java b/youchain-logging/src/main/java/com/youchain/domain/Log.java
new file mode 100644
index 0000000..938bfa7
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/domain/Log.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.domain;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.hibernate.annotations.CreationTimestamp;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-24
+ */
+@Entity
+@Getter
+@Setter
+@Table(name = "sys_log")
+@NoArgsConstructor
+public class Log implements Serializable {
+
+ @Id
+ @Column(name = "log_id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ /** 操作用户 */
+ private String username;
+
+ /** 描述 */
+ private String description;
+
+ /** 方法名 */
+ private String method;
+
+ /** 参数 */
+ private String params;
+
+ /** 返回 */
+ private String returnData;
+
+ /** 日志类型 */
+ private String logType;
+
+ /** 请求ip */
+ private String requestIp;
+
+ /** 地址 */
+ private String address;
+
+ /** 浏览器 */
+ private String browser;
+
+ /** 请求耗时 */
+ private Long time;
+
+ /** 异常详细 */
+ private String exceptionDetail;
+
+ /** 创建日期 */
+ @CreationTimestamp
+ private Timestamp createTime;
+
+ public Log(String logType, Long time) {
+ this.logType = logType;
+ this.time = time;
+ }
+}
diff --git a/youchain-logging/src/main/java/com/youchain/repository/LogRepository.java b/youchain-logging/src/main/java/com/youchain/repository/LogRepository.java
new file mode 100644
index 0000000..a4046d8
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/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.youchain.repository;
+
+import com.youchain.domain.Log;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author Liu Xue
+ * @date 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/youchain-logging/src/main/java/com/youchain/rest/LogController.java b/youchain-logging/src/main/java/com/youchain/rest/LogController.java
new file mode 100644
index 0000000..b77bc56
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/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.youchain.rest;
+
+import com.youchain.utils.SecurityUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import com.youchain.annotation.Log;
+import com.youchain.service.LogService;
+import com.youchain.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;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-24
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/logs")
+@Api(tags = "系统:日志管理")
+public class LogController {
+
+ private final LogService logService;
+
+ @Log("导出数据")
+ @ApiOperation("导出数据")
+ @GetMapping(value = "/download")
+ @PreAuthorize("@el.check()")
+ public void exportLog(HttpServletResponse response, LogQueryCriteria criteria) throws Exception {
+ 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 Exception {
+ 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.setUsername(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/youchain-logging/src/main/java/com/youchain/service/LogService.java b/youchain-logging/src/main/java/com/youchain/service/LogService.java
new file mode 100644
index 0000000..461ed0b
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/service/LogService.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.youchain.service;
+
+import com.youchain.service.dto.LogQueryCriteria;
+import com.youchain.domain.Log;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.springframework.data.domain.Pageable;
+import org.springframework.scheduling.annotation.Async;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author Liu Xue
+ * @date 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 日志实体
+ */
+
+ void save(String url,String returnValue,String username, String browser, String ip, JoinPoint joinPoint, Log log);
+
+
+ void saveLog(Log log);
+ /**
+ * 查询异常详情
+ * @param id 日志ID
+ * @return Object
+ */
+ Object findByErrDetail(Long id);
+
+ /**
+ * 导出日志
+ * @param logs 待导出的数据
+ * @param response /
+ * @throws Exception /
+ */
+ void download(List logs, HttpServletResponse response) throws Exception, Exception;
+
+ /**
+ * 删除所有错误日志
+ */
+ void delAllByError();
+
+ /**
+ * 删除所有INFO日志
+ */
+ void delAllByInfo();
+}
diff --git a/youchain-logging/src/main/java/com/youchain/service/dto/LogErrorDTO.java b/youchain-logging/src/main/java/com/youchain/service/dto/LogErrorDTO.java
new file mode 100644
index 0000000..cc85a9c
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/service/dto/LogErrorDTO.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.service.dto;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+/**
+* @author Liu Xue
+* @date 2019-5-22
+*/
+@Data
+public class LogErrorDTO implements Serializable {
+
+ private Long id;
+
+ private String username;
+
+ private String description;
+
+ private String method;
+
+ private String returnData;
+
+ private String params;
+
+ private String browser;
+
+ private String requestIp;
+
+ private String address;
+
+ private Timestamp createTime;
+}
\ No newline at end of file
diff --git a/youchain-logging/src/main/java/com/youchain/service/dto/LogQueryCriteria.java b/youchain-logging/src/main/java/com/youchain/service/dto/LogQueryCriteria.java
new file mode 100644
index 0000000..0f97f1a
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/service/dto/LogQueryCriteria.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.service.dto;
+
+import com.youchain.annotation.Query;
+import lombok.Data;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ * 日志查询类
+ * @author Liu Xue
+ * @date 2019-6-4 09:23:07
+ */
+@Data
+public class LogQueryCriteria {
+
+ @Query(blurry = "username,description,address,requestIp,method,params")
+ private String blurry;
+
+ @Query
+ private String username;
+
+ @Query(type = Query.Type.INNER_LIKE)
+ private String method;
+
+ @Query(type = Query.Type.INNER_LIKE)
+ private String description;
+
+ @Query(type = Query.Type.GREATER_THAN)
+ private Long time;
+
+ @Query
+ private String logType;
+
+ @Query(type = Query.Type.BETWEEN)
+ private List createTime;
+}
diff --git a/youchain-logging/src/main/java/com/youchain/service/dto/LogSmallDTO.java b/youchain-logging/src/main/java/com/youchain/service/dto/LogSmallDTO.java
new file mode 100644
index 0000000..051309a
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/service/dto/LogSmallDTO.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.youchain.service.dto;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+/**
+ * @author Liu Xue
+ * @date 2019-5-22
+ */
+@Data
+public class LogSmallDTO implements Serializable {
+
+ private String description;
+
+ private String requestIp;
+
+ private String returnData;
+
+ private Long time;
+
+ private String address;
+
+ private String browser;
+
+ private Timestamp createTime;
+}
diff --git a/youchain-logging/src/main/java/com/youchain/service/impl/LogServiceImpl.java b/youchain-logging/src/main/java/com/youchain/service/impl/LogServiceImpl.java
new file mode 100644
index 0000000..8b98d13
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/service/impl/LogServiceImpl.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.service.impl;
+
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.youchain.domain.Log;
+import com.youchain.repository.LogRepository;
+import com.youchain.service.LogService;
+import com.youchain.service.dto.LogQueryCriteria;
+import com.youchain.service.mapstruct.LogSmallMapper;
+import com.youchain.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.youchain.service.mapstruct.LogErrorMapper;
+import com.youchain.utils.*;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+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.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.*;
+
+/**
+ * @author Liu Xue
+ * @date 2018-11-24
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+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));
+ }
+ @Async
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void save(String url,String returnValue,String username, String browser, String ip, JoinPoint joinPoint, Log log_data) {
+ if (log_data == null) {
+ throw new IllegalArgumentException("Log 不能为 null!");
+ }
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+ Method method = signature.getMethod();
+ com.youchain.annotation.Log aopLog = method.getAnnotation(com.youchain.annotation.Log.class);
+
+ // 方法路径
+ String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
+
+ // 描述
+ log_data.setDescription(aopLog.value());
+
+ log_data.setRequestIp(ip);
+ log_data.setAddress(StringUtils.getCityInfo(log_data.getRequestIp()));
+ log_data.setMethod(url+"---"+methodName);
+ log_data.setUsername(username);
+ log_data.setParams(getParameter(method, joinPoint.getArgs()));
+ // 记录登录用户,隐藏密码信息
+ if(signature.getName().equals("login") && StringUtils.isNotEmpty(log_data.getParams())){
+ JSONObject obj = JSONUtil.parseObj(log_data.getParams());
+ log_data.setUsername(obj.getStr("username", ""));
+ log_data.setParams(JSONUtil.toJsonStr(Dict.create().set("username", log_data.getUsername())));
+ }
+ log_data.setBrowser(browser);
+ log_data.setReturnData(returnValue);
+ logRepository.save(log_data);
+ }
+
+ @Async
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void saveLog(Log log_data) {
+ if (log_data == null) {
+ throw new IllegalArgumentException("Log 不能为 null!");
+ }
+ logRepository.save(log_data);
+ }
+
+ /**
+ * 根据方法和传入的参数获取请求参数
+ */
+ 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<>(2);
+ String key = parameters[i].getName();
+ if (!StringUtils.isEmpty(requestParam.value())) {
+ key = requestParam.value();
+ }
+ map.put(key, args[i]);
+ argList.add(map);
+ }
+ }
+ if (argList.isEmpty()) {
+ return "";
+ }
+ return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : JSONUtil.toJsonStr(argList);
+ }
+
+ @Override
+ public Object findByErrDetail(Long id) {
+ Log log = logRepository.findById(id).orElseGet(Log::new);
+ ValidationUtil.isNull(log.getId(), "Log", "id", id);
+ String details = log.getExceptionDetail();
+ return Dict.create().set("exception", details+"");
+ }
+
+ @Override
+ public void download(List logs, HttpServletResponse response) throws Exception {
+ 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("异常详情", log.getExceptionDetail()+"");
+ 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/youchain-logging/src/main/java/com/youchain/service/mapstruct/LogErrorMapper.java b/youchain-logging/src/main/java/com/youchain/service/mapstruct/LogErrorMapper.java
new file mode 100644
index 0000000..3bbc46c
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/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.youchain.service.mapstruct;
+
+import com.youchain.base.BaseMapper;
+import com.youchain.domain.Log;
+import com.youchain.service.dto.LogErrorDTO;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * @author Liu Xue
+ * @date 2019-5-22
+ */
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface LogErrorMapper extends BaseMapper {
+
+}
\ No newline at end of file
diff --git a/youchain-logging/src/main/java/com/youchain/service/mapstruct/LogSmallMapper.java b/youchain-logging/src/main/java/com/youchain/service/mapstruct/LogSmallMapper.java
new file mode 100644
index 0000000..776af6c
--- /dev/null
+++ b/youchain-logging/src/main/java/com/youchain/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.youchain.service.mapstruct;
+
+import com.youchain.base.BaseMapper;
+import com.youchain.domain.Log;
+import com.youchain.service.dto.LogSmallDTO;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * @author Liu Xue
+ * @date 2019-5-22
+ */
+@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface LogSmallMapper extends BaseMapper {
+
+}
\ No newline at end of file
diff --git a/youchain-system/DB_SQL.sql b/youchain-system/DB_SQL.sql
new file mode 100644
index 0000000..13c14eb
--- /dev/null
+++ b/youchain-system/DB_SQL.sql
@@ -0,0 +1,254 @@
+#2023-11-3 AGV场景表
+CREATE TABLE `base_agv_scene` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `dept_id` bigint(20) DEFAULT NULL COMMENT '仓库ID',
+ `code` varchar(20) NOT NULL COMMENT '代码',
+ `name` varchar(20) NOT NULL COMMENT '名称',
+ `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '备注',
+ `create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
+ `update_by` varchar(255) DEFAULT NULL COMMENT '修改人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_time` datetime DEFAULT NULL COMMENT '修改时间',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='AGV场景表';
+
+ALTER TABLE `base_area` ADD COLUMN `agv_scene_id` bigint(20) DEFAULT NULL COMMENT 'avg场景id';
+ALTER TABLE `base_item` ADD COLUMN `agv_scene_id` bigint(20) DEFAULT NULL COMMENT 'avg场景id';
+#物料类型字典
+INSERT INTO `sys_dict` (`dict_id`, `name`, `description`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (21, 'item_type', '货物类型', 'admin', 'admin', '2023-11-03 11:49:03', '2023-11-03 11:49:03');
+INSERT INTO `sys_dict_detail` (`detail_id`, `dict_id`, `label`, `value`, `dict_sort`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (69, 21, '前桶', 'QT', 1, 'admin', 'admin', '2023-11-03 11:49:34', '2023-11-03 11:49:34');
+INSERT INTO `sys_dict_detail` (`detail_id`, `dict_id`, `label`, `value`, `dict_sort`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (69, 21, '后桶', 'HT', 2, 'admin', 'admin', '2023-11-03 11:49:34', '2023-11-03 11:49:34');
+INSERT INTO `sys_dict_detail` (`detail_id`, `dict_id`, `label`, `value`, `dict_sort`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (70, 21, '门封', 'MF', 3, 'admin', 'admin', '2023-11-03 13:39:13', '2023-11-03 13:39:13');
+INSERT INTO `sys_dict_detail` (`detail_id`, `dict_id`, `label`, `value`, `dict_sort`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (71, 21, '小件', 'XJ', 4, 'admin', 'admin', '2023-11-03 13:39:24', '2023-11-03 13:39:24');
+INSERT INTO `sys_dict_detail` (`detail_id`, `dict_id`, `label`, `value`, `dict_sort`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (72, 21, 'ZCZ', '轴承座', 5, 'admin', 'admin', '2023-11-03 13:39:39', '2023-11-03 13:39:39');
+
+#入库点位
+ALTER table data_asn_detail add point_id bigint(20) DEFAULT NULL COMMENT '点位序号';
+
+#按钮盒
+alter table base_box add `IP` varchar(50) DEFAULT NULL COMMENT 'IP' ;
+alter table base_box add `lamp_status` varchar(50) DEFAULT '0' COMMENT '指示灯状态';
+alter table base_box add `lamp_code` varchar(50) DEFAULT NULL COMMENT '按钮盒编号';
+
+#指示灯日志
+CREATE TABLE `sys_lamp_log` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `ip` varchar(50) DEFAULT NULL COMMENT 'ip',
+ `button_box` varchar(50) DEFAULT NULL COMMENT '所属按钮盒',
+ `button_code` varchar(50) DEFAULT NULL COMMENT '按钮编码',
+ `operation_type` varchar(50) DEFAULT NULL COMMENT '操作类型',
+ `request_content` varchar(255) DEFAULT NULL COMMENT '请求内容',
+ `return_content` varchar(255) DEFAULT NULL COMMENT '返回内容',
+ `return_state` varchar(50) DEFAULT NULL COMMENT '返回状态',
+ `create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
+ `update_by` varchar(255) DEFAULT NULL COMMENT '修改人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_time` datetime DEFAULT NULL COMMENT '修改时间',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='指示灯日志';
+
+#轴承座物料类型变更
+update base_item it set it.good_type='ZC' where good_type='ZCZ';
+
+
+#data_agv_task 增加 是否扫描字段
+alter table data_agv_task add `be_scan` int(11) DEFAULT NULL COMMENT '是否扫描' ;
+update data_agv_task set be_scan=0 where be_scan is null ;
+
+#机械臂点位物料编码
+ALTER table base_point add item_code VARCHAR(50) COMMENT '点位物料编码';
+
+#点位排,用于门封解锁
+alter table base_point add rows int(11) DEFAULT NULL COMMENT '层' ;
+alter table base_point add col int(11) DEFAULT NULL COMMENT '列' ;
+alter table base_point add line int(11) DEFAULT NULL COMMENT '排' ;
+
+update base_point set rows=0,col=0,line=0 where rows is null;
+#轴承座机械臂表通信配置表
+CREATE TABLE `base_zcjxb` (
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`modbus_tcp_task_finish` tinyint(1) DEFAULT '0' COMMENT 'Modbus-tcp的任务是否启用',
+`modbus_tcp_point` varchar(255) DEFAULT NULL COMMENT 'Modbus-tcp对应的地标点',
+`modbus_tcp_item` varchar(255) DEFAULT NULL COMMENT 'Modbus-tcp对应的物料',
+`modbus_tcp_slave_id` int(11) DEFAULT NULL COMMENT '从机ID',
+`task_off_on_a` tinyint(1) DEFAULT '0' COMMENT 'a车点位是否有任务',
+`task_off_on_b` tinyint(1) DEFAULT '0' COMMENT 'b车点位是否有任务',
+`code` int(11) DEFAULT NULL COMMENT '机械臂机台号',
+`ip` varchar(100) NOT NULL COMMENT 'ip地址',
+`port` int(11) NOT NULL COMMENT '端口号',
+`communication_type` varchar(255) DEFAULT NULL COMMENT '通信类型',
+`address` int(11) DEFAULT NULL COMMENT '地址',
+`data_length` int(11) DEFAULT NULL COMMENT '数据长度',
+`offset_a1` int(11) DEFAULT NULL COMMENT '偏移量-A返回空车',
+`offset_b1` int(11) DEFAULT NULL COMMENT '偏移量-B返回空车',
+`offset_a2` int(11) DEFAULT NULL COMMENT '偏移量-A叫料',
+`offset_b2` int(11) DEFAULT NULL COMMENT '偏移量-B叫料',
+`offset_a3` int(11) DEFAULT NULL COMMENT '偏移量-A车有料',
+`offset_b3` int(11) DEFAULT NULL COMMENT '偏移量-B车有料',
+`point_a1` varchar(255) DEFAULT NULL COMMENT 'A车的地标点',
+`point_b1` varchar(255) DEFAULT NULL COMMENT 'B车的地标点',
+`item_a1` varchar(255) DEFAULT NULL COMMENT 'A车的物料',
+`item_b1` varchar(255) DEFAULT NULL COMMENT 'B车的物料',
+`enabled` tinyint(1) DEFAULT '0' COMMENT '是否启用',
+`create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
+`update_by` varchar(255) DEFAULT NULL COMMENT '更新人',
+`create_time` datetime DEFAULT NULL COMMENT '创建时间',
+`update_time` datetime DEFAULT NULL COMMENT '更新时间',
+PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8 COMMENT='机械臂';
+
+# 添加一个机械臂正在执行的任务名称
+ALTER TABLE `base_zcjxb` ADD COLUMN task_name varchar(255) DEFAULT NULL COMMENT '任务名称';
+
+# 库区管理
+alter TABLE base_area add column working_station varchar(50) DEFAULT NULL COMMENT '所属工位';
+alter TABLE base_area add column point_id bigint(20) DEFAULT NULL COMMENT '缓存库位';
+alter TABLE base_area add column bexb tinyint(1) DEFAULT '0' COMMENT'线边接收';
+alter TABLE base_area add column besh tinyint(1) DEFAULT '0' COMMENT'收货仓库';
+alter TABLE base_area add column bezz tinyint(1) DEFAULT '0' COMMENT'制造库位耗用';
+
+# 生产顺序计划表
+CREATE TABLE `base_production_plan` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `dept_id` bigint(20) DEFAULT NULL COMMENT '仓库ID',
+ `enabled` bit(1) DEFAULT b'0' COMMENT '状态:1启用、0禁用',
+ `big_item_id` bigint(20) DEFAULT NULL COMMENT '完成品番',
+ `working_station` varchar(50) DEFAULT NULL COMMENT '工位',
+ `No` int(7) DEFAULT NULL COMMENT 'No',
+ `machine_no` int(7) DEFAULT NULL COMMENT '机号',
+ `import_date` datetime DEFAULT NULL COMMENT '导入日期',
+ `planned_date` datetime DEFAULT NULL COMMENT '计划日期',
+ `downline_date` datetime DEFAULT NULL COMMENT '下线日期',
+ `take_up_time` datetime DEFAULT NULL COMMENT '耗用时间',
+ `IDNO` varchar(50) DEFAULT NULL COMMENT 'IDNO',
+ `monthly_no` varchar(255) DEFAULT NULL COMMENT '月度序号',
+ `project_no` varchar(255) DEFAULT NULL COMMENT '计划单号',
+ `make_line` varchar(255) DEFAULT NULL COMMENT '制造线',
+ `order_no` bigint(20) DEFAULT NULL COMMENT '序号',
+ `bom_list_id` bigint(20) DEFAULT NULL COMMENT '工位清单',
+ `sh_area_id` bigint(20) DEFAULT NULL COMMENT '收货仓库',
+ `rk_area_id` bigint(20) DEFAULT NULL COMMENT '入库库区',
+ `off_line_part_id` bigint(20) DEFAULT NULL COMMENT '下线零件ID',
+ `pick_plan_id` bigint(20) DEFAULT NULL COMMENT '备货计划ID',
+ `type` varchar(255) DEFAULT NULL COMMENT '出库类型',
+ `part_variety` varchar(255) DEFAULT NULL COMMENT '部品种类',
+ `statue` varchar(255) DEFAULT NULL COMMENT '耗用状态',
+ `auto_production_id` bigint(20) DEFAULT NULL COMMENT '所属自动计划',
+ `description` varchar(255) DEFAULT NULL COMMENT '描述',
+ `create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
+ `update_by` varchar(255) DEFAULT NULL COMMENT '更新人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_time` datetime DEFAULT NULL COMMENT '修改日期',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `bpp_key` (`working_station`,`IDNO`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='生产顺序计划';
+
+# 部品品番 添加库位字段
+ALTER table base_item add point_id bigint(20) DEFAULT NULL COMMENT '库位';
+
+# 收货管理表
+CREATE TABLE `data_asn` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `code` varchar(20) CHARACTER SET utf8 NOT NULL COMMENT '单号',
+ `area_id` bigint(20) DEFAULT NULL COMMENT '库区',
+ `status` varchar(255) DEFAULT NULL COMMENT '状态',
+ `cus_code` varchar(255) DEFAULT NULL COMMENT '客户订单号',
+ `related_bill1` varchar(255) DEFAULT NULL COMMENT '相关单号1',
+ `related_bill2` varchar(255) DEFAULT NULL COMMENT '相关单号2',
+ `related_bill3` varchar(255) DEFAULT NULL COMMENT '相关单号3',
+ `order_date`datetime DEFAULT NULL DEFAULT NULL COMMENT '订单日期',
+ `estimate_date`datetime DEFAULT NULL COMMENT '预计到货日期',
+ `received_date`datetime DEFAULT NULL COMMENT '收货日期',
+ `from_name` varchar(255) DEFAULT NULL COMMENT '发货方',
+ `from_address` varchar(255) DEFAULT NULL COMMENT '发货地址',
+ `from_man` varchar(255) DEFAULT NULL COMMENT '发货联系人',
+ `from_tel` varchar(255) DEFAULT NULL COMMENT '发货电话',
+ `order_quantity` double DEFAULT '0' COMMENT '订单数量',
+ `received_quantity` double DEFAULT '0' COMMENT '收货数量',
+ `putaway_quantity` double DEFAULT '0' COMMENT '上架数量',
+ `vehicle` varchar(255) DEFAULT NULL COMMENT '车牌号',
+ `bill_type_id` varchar(255) DEFAULT NULL COMMENT '单据类型',
+ `dept_id` bigint(20) DEFAULT NULL COMMENT '仓库ID',
+ `description` varchar(255) DEFAULT NULL COMMENT '备注',
+ `create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
+ `update_by` varchar(255) DEFAULT NULL COMMENT '修改人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_time` datetime DEFAULT NULL COMMENT '修改时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `code` (`code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收货管理';
+# 出库添加关联主表的字段
+ALTER table data_pick_detail add pick_ticket bigint(20) DEFAULT NULL COMMENT '出库管理主表';
+# 出库管理
+CREATE TABLE `data_pick_ticket` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `area` bigint(20) DEFAULT NULL COMMENT '出库库区',
+ `sh_area` bigint(20) DEFAULT NULL COMMENT '收货库区',
+ `code` varchar(20) NOT NULL COMMENT '单号',
+ `status` varchar(255) DEFAULT NULL COMMENT '状态',
+ `cus_code` varchar(20) DEFAULT NULL COMMENT '客户订单号',
+ `related_bill1` varchar(255) DEFAULT NULL COMMENT '相关单号1',
+ `related_bill2` varchar(255) DEFAULT NULL COMMENT '相关单号2',
+ `related_bill3` varchar(255) DEFAULT NULL COMMENT '相关单号3',
+ `order_date` datetime DEFAULT NULL COMMENT '订单日期',
+ `ship_date` datetime DEFAULT NULL COMMENT '发货日期',
+ `fh_by` varchar(255) DEFAULT NULL COMMENT '发货人',
+ `received_date` datetime DEFAULT NULL COMMENT '到达日期',
+ `sl_by` varchar(255) DEFAULT NULL COMMENT '接收人',
+ `sl_qty` double DEFAULT '0' COMMENT '收料数量',
+ `tl_date` time DEFAULT NULL COMMENT '投料日期',
+ `tl_by` varchar(255) DEFAULT NULL COMMENT '投料人',
+ `tl_qty` double DEFAULT '0' COMMENT '投料数量',
+ `ship_to_name` varchar(255) DEFAULT NULL COMMENT '收货方',
+ `ship_address` varchar(255) DEFAULT NULL COMMENT '收货地址',
+ `ship_man` varchar(255) DEFAULT NULL COMMENT '收货联系人',
+ `ship_tel` varchar(255) DEFAULT NULL COMMENT '收货电话',
+ `order_quantity` double DEFAULT '0' COMMENT '订单数量',
+ `allocated_quantity` double DEFAULT '0' COMMENT '出单数量',
+ `picked_quantity` double DEFAULT '0' COMMENT '拣货数量',
+ `shipped_quantity` double DEFAULT '0' COMMENT '发运数量',
+ `xb_qty` double DEFAULT '0' COMMENT '线边数量',
+ `zt_qty` double DEFAULT '0' COMMENT '在途数量',
+ `xq_qty` double DEFAULT '0' COMMENT '需求数量',
+ `bh_qty` double DEFAULT '0' COMMENT '备货数量',
+ `vehicle` varchar(255) DEFAULT NULL COMMENT '车牌号',
+ `bill_type` bigint(20) DEFAULT NULL COMMENT '单据类型',
+ `bp_type` bigint(20) DEFAULT NULL COMMENT '部品种类',
+ `dept_id` bigint(20) DEFAULT NULL COMMENT '仓库ID',
+ `description` varchar(255) DEFAULT NULL COMMENT '备注',
+ `create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
+ `update_by` varchar(255) DEFAULT NULL COMMENT '修改人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_time` datetime DEFAULT NULL COMMENT '修改时间',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `dpt` (`code`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='出库管理';
+
+# 新政字段
+ALTER table data_pick_detail add `point_id` bigint(20) DEFAULT NULL COMMENT '点位';
+# xppRecord增加状态字段
+ALTER table `data_xpp_record` add `status` varchar(255) DEFAULT NULL COMMENT '状态';
+ALTER TABLE `data_xpp_record` MODIFY COLUMN `nrs` INT(11);
+# inventory 加字段
+ALTER table `data_inventory` add `area_id` bigint(20) DEFAULT NULL COMMENT '库区';
+ALTER table `data_inventory` add `zzkw` bigint(20) DEFAULT NULL COMMENT '制造库位';
+# InventoryLog
+ALTER table `data_inventory_log` add `area_id` bigint(20) DEFAULT NULL COMMENT '库区';
+ALTER table `data_inventory_log` add `zzkw` bigint(20) DEFAULT NULL COMMENT '制造库位';
+ALTER table `data_inventory_log` add `zckw` bigint(20) DEFAULT NULL COMMENT '暂存库位';
+# Task
+ALTER table `data_task` add `area_id` bigint(20) DEFAULT NULL COMMENT '库区';
+ALTER table `data_task` add `zzkw` bigint(20) DEFAULT NULL COMMENT '制造库位';
+# sys_dept 表添加代码字段
+ALTER table `sys_dept` add `code` varchar(255) DEFAULT NULL COMMENT '代码';
+# 备货页面需要加的字段
+ALTER table data_pick_ticket add `pure_req_qty` double DEFAULT '0' COMMENT '纯需求数量';
+ALTER table data_pick_ticket add `prep_re` double DEFAULT '0' COMMENT '备货需求数量';
+ALTER table data_pick_ticket add `out_order_date` datetime DEFAULT NULL COMMENT '出单日期';
+ALTER table data_pick_ticket add `stocking_date` datetime DEFAULT NULL COMMENT '备货日期';
+# 出库单明细
+ALTER table data_pick_detail add `xq_qty` double DEFAULT '0' COMMENT '需求数量';
+ALTER table data_pick_detail add `pure_req_qty` double DEFAULT '0' COMMENT '纯需求数量';
+ALTER table data_pick_detail add `xb_qty` double DEFAULT '0' COMMENT '线边数量';
+ALTER table data_pick_detail add `y_stk_demand_qty` double DEFAULT '0' COMMENT '原备货需求数量';
+ALTER table data_pick_detail add `y_req_qty` double DEFAULT '0' COMMENT '原纯需求数';
diff --git a/youchain-system/pom.xml b/youchain-system/pom.xml
new file mode 100644
index 0000000..dcc2ba9
--- /dev/null
+++ b/youchain-system/pom.xml
@@ -0,0 +1,152 @@
+
+
+
+ youchain
+ com.youchain
+ 2.6
+
+ 4.0.0
+
+ youchain-system
+ 核心模块
+
+
+ 0.11.2
+
+ 5.8.0
+
+
+
+
+
+ com.intelligt.modbus
+ jlibmodbus
+ 1.2.9.7
+
+
+
+ com.youchain
+ youchain-generator
+ 2.6
+
+
+ com.youchain
+ youchain-common
+
+
+
+
+
+
+
+
+ com.youchain
+ youchain-tongyong
+ 2.6
+
+
+
+
+ com.youchain
+ youchain-tools
+ 2.6
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+
+
+ org.quartz-scheduler
+ quartz
+
+
+
+
+ ch.ethz.ganymed
+ ganymed-ssh2
+ build210
+
+
+ com.jcraft
+ jsch
+ 0.1.55
+
+
+
+
+ com.github.oshi
+ oshi-core
+ 6.1.4
+
+
+ com.youchain
+ youchain-logging
+ 2.6
+ compile
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jjwt.version}
+
+
+
+ io.netty
+ netty-all
+ 4.1.42.Final
+
+
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
diff --git a/youchain-system/src/main/java/com/youchain/AppRun.java b/youchain-system/src/main/java/com/youchain/AppRun.java
new file mode 100644
index 0000000..12f6b07
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/AppRun.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain;
+
+import cn.hutool.json.JSONUtil;
+import com.youchain.annotation.rest.AnonymousGetMapping;
+import com.youchain.modules.license.AGxServerInfos;
+import com.youchain.modules.license.LicenseValidate;
+import com.youchain.modules.license.LinuxServerInfos;
+import com.youchain.modules.license.WindowsServerInfos;
+import com.youchain.utils.SpringContextHolder;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 开启审计功能 -> @EnableJpaAuditing
+ *
+ * @author Liu Xue
+ * @date 2018/11/15 9:20:19
+ */
+@EnableAsync
+@RestController
+@Api(hidden = true)
+@SpringBootApplication
+@EnableTransactionManagement
+@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class})
+@EnableJpaAuditing(auditorAwareRef = "auditorAware")
+@Slf4j
+public class AppRun {
+ //@SpringBootApplication(scanBasePackages = {"org.jeecg.modules.jmreport","me.zhengjie"})
+ public static void main(String[] args) {
+ SpringApplication springApplication = new SpringApplication(AppRun.class);
+ // 监控应用的PID,启动时可指定PID路径:--spring.pid.file=/home/eladmin/app.pid
+ // 或者在 application.yml 添加文件路径,方便 kill,kill `cat /home/eladmin/app.pid`
+ springApplication.addListeners(new ApplicationPidFileWriter());
+ springApplication.run(args);
+
+ log.error(JSONUtil.toJsonStr(LicenseValidate.getDeviceInfo()));
+
+ }
+
+ @Bean
+ public SpringContextHolder springContextHolder() {
+ return new SpringContextHolder();
+ }
+
+ /**
+ * 访问首页提示
+ *
+ * @return /
+ */
+ @AnonymousGetMapping("/")
+ public String index() {
+ return "Backend service started successfully";
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/DuplicateSubmission/DuplicateSubmission.java b/youchain-system/src/main/java/com/youchain/DuplicateSubmission/DuplicateSubmission.java
new file mode 100644
index 0000000..f2c93c7
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/DuplicateSubmission/DuplicateSubmission.java
@@ -0,0 +1,13 @@
+package com.youchain.DuplicateSubmission;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DuplicateSubmission {
+
+ int value() default 5;
+}
diff --git a/youchain-system/src/main/java/com/youchain/DuplicateSubmission/DuplicateSubmissionAspect.java b/youchain-system/src/main/java/com/youchain/DuplicateSubmission/DuplicateSubmissionAspect.java
new file mode 100644
index 0000000..50965f8
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/DuplicateSubmission/DuplicateSubmissionAspect.java
@@ -0,0 +1,123 @@
+package com.youchain.DuplicateSubmission;
+
+import com.alibaba.fastjson.JSON;
+
+import com.youchain.exception.BadRequestException;
+import com.youchain.utils.RedisUtils;
+import com.youchain.utils.RequestHolder;
+import com.youchain.utils.SpringContextHolder;
+import com.youchain.utils.StringUtils;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Aspect
+@Component
+public class DuplicateSubmissionAspect {
+
+ // @Around("@annotation(com.example.demo.LogExecutionTime)")表示该环绕通知仅在使用@LogExecutionTime注解的方法上执行
+ @Around("@annotation(duplicateSubmission)")
+ public Object logExecutionTime(ProceedingJoinPoint joinPoint,DuplicateSubmission duplicateSubmission) throws Throwable {
+
+ int value = duplicateSubmission.value();
+
+
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+ Method method = signature.getMethod();
+ String parm1=getParameter(method, joinPoint.getArgs());
+ HttpServletRequest request = RequestHolder.getHttpServletRequest();
+ String parm=handleParm(request);
+ String url=handlerUrl(request);
+ RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
+ String key=url+"-"+parm1+"-"+parm;
+ if(redisUtils.hasKey(key)){
+ throw new BadRequestException("操作过快,请稍后重试");
+ }
+ redisUtils.set(key,"",value);
+ // 执行目标方法
+ Object result = joinPoint.proceed();
+ System.out.println("请求参数为:"+key);
+
+ redisUtils.del(key);
+ return result;
+ }
+
+
+ private String handleParm( HttpServletRequest request) {
+ if (request == null) {
+ return "";
+ }
+ String parm="";
+ try {
+ parm=request.getQueryString();
+ } catch (Exception e) {
+ parm="";
+ System.out.println("parm获取失败");
+ }
+ if(parm==null||parm.isEmpty()){
+ parm="";
+ }
+ return parm;
+ }
+
+ private String getParameter(Method method, Object[] args) {
+ List argList = new ArrayList<>();
+ Parameter[] parameters = method.getParameters();
+ for (int i = 0; i < parameters.length; i++) {
+ // 过滤掉不能序列化的类型: MultiPartFile
+ if (args[i] instanceof MultipartFile) {
+ continue;
+ }
+ //将RequestBody注解修饰的参数作为请求参数
+ RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
+ if (requestBody != null) {
+ argList.add(args[i]);
+ }
+ //将RequestParam注解修饰的参数作为请求参数
+ RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
+ if (requestParam != null) {
+ Map map = new HashMap<>(2);
+ String key = parameters[i].getName();
+ if (!StringUtils.isEmpty(requestParam.value())) {
+ key = requestParam.value();
+ }
+ map.put(key, args[i]);
+ argList.add(map);
+ }
+ }
+ if (argList.isEmpty()) {
+ return "";
+ }
+ return argList.size() == 1 ? JSON.toJSONString(argList.get(0)) : JSON.toJSONString(argList);
+ }
+
+ private String handlerUrl( HttpServletRequest request) {
+ if (request == null) {
+ return "";
+ }
+ String url="";
+ try {
+ url=request.getRequestURL().toString();
+ } catch (Exception e) {
+ url="";
+ }
+ if(url==null||url.isEmpty()){
+ url="";
+ }
+ return url;
+ }
+}
+
diff --git a/youchain-system/src/main/java/com/youchain/Netty/HexTools.java b/youchain-system/src/main/java/com/youchain/Netty/HexTools.java
new file mode 100644
index 0000000..441fc9e
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/HexTools.java
@@ -0,0 +1,44 @@
+package com.youchain.Netty;
+
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class HexTools {
+
+ //十六进制字符转十进制
+ public static int covert(String content){
+ int number=0;
+ String [] HighLetter = {"A","B","C","D","E","F"};
+ Map map = new HashMap<>();
+ for(int i = 0;i <= 9;i++){
+ map.put(i+"",i);
+ }
+ for(int j= 10;j out) throws Exception {
+ /* ByteBuf frame = in.retainedDuplicate();
+ final String content = frame.toString(CharsetUtil.UTF_8);
+ log.error("content:"+content);
+ list.add(content);
+ in.skipBytes(in.readableBytes());*/
+
+
+ String HEXES = "0123456789ABCDEF";
+ byte[] req = new byte[in.readableBytes()];
+ in.readBytes(req);
+ final StringBuilder hex = new StringBuilder(2 * req.length);
+
+ for (int i = 0; i < req.length; i++) {
+ byte b = req[i];
+ hex.append(HEXES.charAt((b & 0xF0) >> 4))
+ .append(HEXES.charAt((b & 0x0F)));
+ }
+ out.add(hex.toString());
+ }
+}
+
diff --git a/youchain-system/src/main/java/com/youchain/Netty/MessageEncodeHandler.java b/youchain-system/src/main/java/com/youchain/Netty/MessageEncodeHandler.java
new file mode 100644
index 0000000..6bf15da
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/MessageEncodeHandler.java
@@ -0,0 +1,21 @@
+package com.youchain.Netty;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+import io.netty.util.CharsetUtil;
+
+public class MessageEncodeHandler extends MessageToByteEncoder {
+ // 数据分割符
+ String delimiter;
+
+ public MessageEncodeHandler(String delimiter) {
+ this.delimiter = delimiter;
+ }
+
+ @Override
+ protected void encode(ChannelHandlerContext channelHandlerContext, String message, ByteBuf out) throws Exception {
+ out.writeBytes((message + delimiter).getBytes(CharsetUtil.UTF_8));
+ }
+}
+
diff --git a/youchain-system/src/main/java/com/youchain/Netty/NettyConfig.java b/youchain-system/src/main/java/com/youchain/Netty/NettyConfig.java
new file mode 100644
index 0000000..226ea97
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/NettyConfig.java
@@ -0,0 +1,58 @@
+package com.youchain.Netty;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties
+public class NettyConfig {
+ final NettyProperties nettyProperties;
+
+ public NettyConfig(NettyProperties nettyProperties) {
+ this.nettyProperties = nettyProperties;
+ }
+
+ /**
+ * boss线程池-进行客户端连接
+ *
+ * @return
+ */
+ @Bean
+ public NioEventLoopGroup boosGroup() {
+ return new NioEventLoopGroup(nettyProperties.getBoss());
+ }
+
+ /**
+ * worker线程池-进行业务处理
+ *
+ * @return
+ */
+ @Bean
+ public NioEventLoopGroup workerGroup() {
+ return new NioEventLoopGroup(nettyProperties.getWorker());
+ }
+
+ /**
+ * 服务端启动器,监听客户端连接
+ *
+ * @return
+ */
+ @Bean
+ public ServerBootstrap serverBootstrap() {
+ ServerBootstrap serverBootstrap = new ServerBootstrap()
+ // 指定使用的线程组
+ .group(boosGroup(), workerGroup())
+ // 指定使用的通道
+ .channel(NioServerSocketChannel.class)
+ // 指定连接超时时间
+ .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyProperties.getTimeout())
+ // 指定worker处理器
+ .childHandler(new NettyServerHandler());
+ return serverBootstrap;
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/Netty/NettyProperties.java b/youchain-system/src/main/java/com/youchain/Netty/NettyProperties.java
new file mode 100644
index 0000000..cb7399b
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/NettyProperties.java
@@ -0,0 +1,90 @@
+package com.youchain.Netty;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "netty")
+public class NettyProperties {
+
+ /**
+ * boss线程数量
+ */
+ private Integer boss;
+
+ /**
+ * worker线程数量
+ */
+ private Integer worker;
+
+ /**
+ * 连接超时时间
+ */
+ private Integer timeout = 30000;
+
+ /**
+ * 服务器主端口
+ */
+ private Integer port = 8502;
+
+ /**
+ * 服务器备用端口
+ */
+ private Integer portSalve = 8503;
+
+ /**
+ * 服务器地址 默认为本地
+ */
+ private String host = "127.0.0.1";
+
+ public Integer getBoss() {
+ return boss;
+ }
+
+ public void setBoss(Integer boss) {
+ this.boss = boss;
+ }
+
+ public Integer getWorker() {
+ return worker;
+ }
+
+ public void setWorker(Integer worker) {
+ this.worker = worker;
+ }
+
+ public Integer getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(Integer timeout) {
+ this.timeout = timeout;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(Integer port) {
+ this.port = port;
+ }
+
+ public Integer getPortSalve() {
+ return portSalve;
+ }
+
+ public void setPortSalve(Integer portSalve) {
+ this.portSalve = portSalve;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ // setter、getter 。。。。
+
+}
diff --git a/youchain-system/src/main/java/com/youchain/Netty/NettyServerBoot.java b/youchain-system/src/main/java/com/youchain/Netty/NettyServerBoot.java
new file mode 100644
index 0000000..e3d3be0
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/NettyServerBoot.java
@@ -0,0 +1,54 @@
+package com.youchain.Netty;
+
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.nio.NioEventLoopGroup;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.annotation.Resource;
+
+@Component
+@Slf4j
+public class NettyServerBoot {
+
+ @Resource
+ NioEventLoopGroup boosGroup;
+ @Resource
+ NioEventLoopGroup workerGroup;
+ final ServerBootstrap serverBootstrap;
+ final NettyProperties nettyProperties;
+
+ public NettyServerBoot(ServerBootstrap serverBootstrap, NettyProperties nettyProperties) {
+ this.serverBootstrap = serverBootstrap;
+ this.nettyProperties = nettyProperties;
+ }
+
+
+ /**
+ * 启动netty
+ *
+ * @throws InterruptedException
+ */
+ @PostConstruct
+ public void start() throws InterruptedException {
+ // 绑定端口启动
+ serverBootstrap.bind(nettyProperties.getPort()).sync();
+ // 备用端口
+ serverBootstrap.bind(nettyProperties.getPortSalve()).sync();
+ log.info("启动Netty: {},{}", nettyProperties.getPort(), nettyProperties.getPortSalve());
+ }
+
+ /**
+ * 关闭netty
+ */
+ @PreDestroy
+ public void close() {
+ log.info("关闭Netty");
+ boosGroup.shutdownGracefully();
+ workerGroup.shutdownGracefully();
+ }
+}
+
diff --git a/youchain-system/src/main/java/com/youchain/Netty/NettyServerHandler.java b/youchain-system/src/main/java/com/youchain/Netty/NettyServerHandler.java
new file mode 100644
index 0000000..8ca6544
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/NettyServerHandler.java
@@ -0,0 +1,27 @@
+package com.youchain.Netty;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+
+public class NettyServerHandler extends ChannelInitializer {
+ @Override
+ protected void initChannel(SocketChannel socketChannel) throws Exception {
+ // 数据分割符
+ //String delimiterStr = "\r\n";
+ //ByteBuf delimiter = Unpooled.copiedBuffer(delimiterStr.getBytes());
+ ChannelPipeline pipeline = socketChannel.pipeline();
+ // 使用自定义处理拆包/沾包,并且每次查找的最大长度为1024字节
+ //pipeline.addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
+ // 将上一步解码后的数据转码为Message实例
+ pipeline.addLast(new MessageDecodeHandler());
+ // 对发送客户端的数据进行编码,并添加数据分隔符
+ pipeline.addLast(new MessageEncodeHandler(""));
+ // 对数据进行最终处理
+ pipeline.addLast(new ServerListenerHandler());
+ }
+}
+
diff --git a/youchain-system/src/main/java/com/youchain/Netty/NettyUtils.java b/youchain-system/src/main/java/com/youchain/Netty/NettyUtils.java
new file mode 100644
index 0000000..203bed8
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/NettyUtils.java
@@ -0,0 +1,233 @@
+package com.youchain.Netty;
+
+import com.youchain.utils.RedisUtils;
+import com.youchain.utils.SpringContextHolder;
+import com.youchain.utils.StringUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import lombok.extern.slf4j.Slf4j;
+
+import java.net.InetSocketAddress;
+@Slf4j
+public class NettyUtils {
+
+ public static final String button_1="0001";
+ public static final String button_2="0002";
+ public static final String button_3="0003";
+ public static final String button_4="0004";
+
+ private static final String button_on="0001";
+ private static final String button_off="0000";
+
+ public static final String light_1="0005";
+ public static final String light_2="0006";
+ public static final String light_3="0007";
+ public static final String light_4="0008";
+
+
+ private static final String light_off="0000";
+ private static final String light_on="0001";
+
+ private static final String light_fast="0002";
+
+ private static final String light_slow="0003";
+ /**
+ * 灯光熄灭
+ * @param ip 按钮盒ip
+ * @param index 位置码
+ * @param lamp_log_id 日志id 如果是null为新增
+ */
+ public static void light_off(String ip,String index,Long lamp_log_id){
+ Channel channel= getChannel(ip);
+ //4位通讯帧号
+ //4位通讯协议
+ //4位数据长度(在这后面的总长度)
+ //2位设备地址 01
+ //2位功能码 06 写入单个数据
+ //4位寄存器地址 (按钮/灯)
+ //4位数据 (按钮 0没有被按下,1按钮被按下)(指示灯 0灭,1亮,2快闪,3慢闪)
+ String content="0001"+"0000"+"0006"+"01"+"06"+index+light_off;
+ writeToClient(lamp_log_id,content,channel,"灯光熄灭");
+ }
+ /**
+ * 灯光常亮
+ * @param ip 按钮盒ip
+ * @param index 位置码light_x
+ * @param lamp_log_id 日志id 如果是null为新增
+ */
+ public static void light_on(String ip,String index,Long lamp_log_id){
+ Channel channel= getChannel(ip);
+ //4位通讯帧号
+ //4位通讯协议
+ //4位数据长度(在这后面的总长度)
+ //2位设备地址 01
+ //2位功能码 06 写入单个数据
+ //4位寄存器地址 (按钮/灯)
+ //4位数据 (按钮 0没有被按下,1按钮被按下)(指示灯 0灭,1亮,2快闪,3慢闪)
+ String content="0001"+"0000"+"0006"+"01"+"06"+index+light_on;
+ writeToClient(lamp_log_id,content,channel,"灯光常亮");
+ }
+ /**
+ * 灯光快闪
+ * @param ip 按钮盒ip
+ * @param index 位置码
+ * @param lamp_log_id 日志id 如果是null为新增
+ */
+ public static void light_on_fast_flicker(String ip,String index,Long lamp_log_id){
+ Channel channel= getChannel(ip);
+ //4位通讯帧号
+ //4位通讯协议
+ //4位数据长度(在这后面的总长度)
+ //2位设备地址 01
+ //2位功能码 06 写入单个数据
+ //4位寄存器地址 (按钮/灯)
+ //4位数据 (按钮 0没有被按下,1按钮被按下)(指示灯 0灭,1亮,2快闪,3慢闪)
+ String content="0001"+"0000"+"0006"+"01"+"06"+index+light_fast;
+ writeToClient(lamp_log_id,content,channel,"灯光快闪");
+ }
+
+ /**
+ * 灯光慢闪
+ * @param ip 按钮盒ip
+ * @param index 位置码
+ * @param lamp_log_id 日志id 如果是null为新增
+ */
+ public static void light_on_slow_flicker(String ip,String index,Long lamp_log_id){
+ Channel channel= getChannel(ip);
+ //4位通讯帧号
+ //4位通讯协议
+ //4位数据长度(在这后面的总长度)
+ //2位设备地址 01
+ //2位功能码 06 写入单个数据
+ //4位寄存器地址 (按钮/灯)
+ //4位数据 (按钮 0没有被按下,1按钮被按下)(指示灯 0灭,1亮,2快闪,3慢闪)
+ String content="0001"+"0000"+"0006"+"01"+"06"+index+light_slow;
+ writeToClient(lamp_log_id,content,channel,"灯光慢闪");
+ }
+
+
+ /**
+ * 按钮释放
+ * @param ip 按钮盒ip
+ * @param index 位置码button_x
+ * @param lamp_log_id 日志id 如果是null为新增
+ */
+ public static void button_off(String ip,String index,Long lamp_log_id){
+ Channel channel= getChannel(ip);
+ //4位通讯帧号
+ //4位通讯协议
+ //4位数据长度(在这后面的总长度)
+ //2位设备地址 01
+ //2位功能码 06 写入单个数据
+ //4位寄存器地址 (按钮/灯)
+ //4位数据 (按钮 0没有被按下,1按钮被按下)(指示灯 0灭,1亮,2快闪,3慢闪)
+ String content="0001"+"0000"+"0006"+"01"+"06"+index+button_off;
+ writeToClient(lamp_log_id,content,channel,"按钮释放");
+ }
+
+ /**
+ * 按钮按下
+ * @param ip 按钮盒ip
+ * @param index 位置码
+ * @param lamp_log_id 日志id 如果是null为新增
+ */
+ public static void button_on(String ip,String index,Long lamp_log_id){
+ Channel channel= getChannel(ip);
+ //4位通讯帧号
+ //4位通讯协议
+ //4位数据长度(在这后面的总长度)
+ //2位设备地址 01
+ //2位功能码 06 写入单个数据
+ //4位寄存器地址 (按钮/灯)
+ //4位数据 (按钮 0没有被按下,1按钮被按下)(指示灯 0灭,1亮,2快闪,3慢闪)
+ String content="0001"+"0000"+"0006"+"01"+"06"+index+button_on;
+ writeToClient(lamp_log_id,content,channel,"按钮按下");
+
+ }
+
+
+ public static void sendMsg(String ip,String content,Long lamp_log_id){
+ Channel channel= getChannel(ip);
+ writeToClient(lamp_log_id,content,channel,"测试");
+ }
+
+ public static Channel getChannel(String ip){
+ for (Channel client : ServerListenerHandler.clients) {
+ String devce_ip =((InetSocketAddress)client.remoteAddress()).getAddress().getHostAddress();
+ if(ip.equals(devce_ip)){
+ return client;
+ }
+ }
+ return null;
+ }
+
+
+
+ public static void writeToClient(final Long lamp_log_id,final String sendStr, Channel channel, final String mark) {
+ //加载redis
+ //000000000006010300010008
+ //000100000006010600060000
+
+ if("000000000006010300010008".equals(sendStr)){
+ log.info("回写心跳,执行一次"+sendStr);
+ ReawriteToClient(lamp_log_id,sendStr,channel,mark);
+ }else{
+ log.info("其他数据,执行两次"+sendStr);
+ ReawriteToClient(lamp_log_id,sendStr,channel,mark);
+ try{
+ Thread.sleep(100);
+ }catch (Exception e){
+
+ }
+ ReawriteToClient(lamp_log_id,sendStr,channel,mark);
+ }
+
+ }
+
+
+ public static void ReawriteToClient(final Long lamp_log_id,final String sendStr, Channel channel, final String mark) {
+ //加载redis
+ RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
+ if(channel==null){
+ //"设备IP无效";
+ if (lamp_log_id!=null){
+ redisUtils.set(String.valueOf(lamp_log_id),"设备IP无效");
+ }
+ return;
+ }
+ try {
+ ByteBuf bufff = Unpooled.buffer();//netty需要用ByteBuf传输
+ bufff.writeBytes(HexTools.hexString2Bytes(sendStr));//对接需要16进制
+ channel.writeAndFlush(bufff).addListener(new ChannelFutureListener() {
+ @Override
+ public void operationComplete(ChannelFuture future) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ if(!StringUtils.isEmpty(mark)){
+ sb.append("【").append(mark).append("】");
+ }
+ if (future.isSuccess()) {
+ log.info(sb.toString()+"回写成功"+sendStr);
+ if (lamp_log_id!=null){
+ redisUtils.set(String.valueOf(lamp_log_id),sb.toString()+"回写成功"+sendStr);
+ }
+ } else {
+ log.error(sb.toString()+"回写失败"+sendStr);
+ if (lamp_log_id!=null){
+ redisUtils.set(String.valueOf(lamp_log_id),sb.toString()+"回写失败"+sendStr);
+ }
+ }
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error("调用通用writeToClient()异常"+e.getMessage());
+ if (lamp_log_id!=null){
+ redisUtils.set(String.valueOf(lamp_log_id), "调用通用writeToClient()异常"+e.getMessage());
+ }
+ }
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/Netty/ServerListenerHandler.java b/youchain-system/src/main/java/com/youchain/Netty/ServerListenerHandler.java
new file mode 100644
index 0000000..73c46c9
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/Netty/ServerListenerHandler.java
@@ -0,0 +1,257 @@
+package com.youchain.Netty;
+
+import cn.hutool.json.JSONUtil;
+import com.youchain.basicdata.domain.Box;
+import com.youchain.basicdata.repository.BoxRepository;
+import com.youchain.basicdata.service.BoxService;
+import com.youchain.basicdata.service.dto.BoxDto;
+import com.youchain.basicdata.service.dto.BoxQueryCriteria;
+import com.youchain.basicdata.service.impl.BoxServiceImpl;
+import com.youchain.basicdata.service.impl.BoxServiceImpl;
+import com.youchain.basicdata.service.mapstruct.BoxMapper;
+import com.youchain.domain.Log;
+import com.youchain.exception.handler.ApiResult;
+import com.youchain.service.impl.LogServiceImpl;
+import com.youchain.utils.RedisUtils;
+import com.youchain.utils.SpringContextHolder;
+import com.youchain.utils.StringUtils;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.net.InetSocketAddress;
+import java.util.List;
+
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.OK;
+
+@Slf4j
+public class ServerListenerHandler extends SimpleChannelInboundHandler {
+
+
+ public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+
+
+ /**
+ * 设备接入连接时处理
+ *
+ * @param ctx
+ */
+ @Override
+ public void handlerAdded(ChannelHandlerContext ctx) {
+ String ip =((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress();
+ log.info("有新的连接:[{}]", ip);
+ Channel lastClient=NettyUtils.getChannel(ip);
+ if(lastClient!=null){
+ log.info("当前IP有旧的连接,移除旧的的连接:[{}]", ip);
+ clients.remove(lastClient);
+ }
+ clients.add(ctx.channel());
+
+
+ }
+
+ /**
+ * 数据处理
+ *
+ * @param ctx
+ * @param content
+ */
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, String content) {
+ String ip =((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress();
+ // 获取消息实例中的消息体
+ // 对不同消息类型进行处理
+ //00 00 /00 00 /00 0C /00 /07 /00 00 00 00 00 00 00 00 00 01
+ //4位通讯帧号
+ //4位通讯协议
+ //4位数据长度(在这后面的总长度)
+ //2位设备地址 00
+ //2位功能码 07 心跳数据
+ //16 位 按钮1-按钮8 的状态
+ //4位数据 呼叫器编号
+
+ String key="TCP"+ip;
+
+ if(content.length()==36){
+ RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
+
+ int time=(int) redisUtils.get(key,10);
+
+ if(time>=10000){
+ time=10;
+ }
+
+ redisUtils.set(key,time+1);
+
+ if(time%8==0){
+ StringBuffer buff=new StringBuffer();
+ buff.append("0000");//通讯帧数
+ buff.append("0000");//协议类型
+ buff.append("0006");//长度
+ buff.append("01");//设备地址
+ buff.append("03");//读取数据
+ buff.append("0001");//读取目标数据的起始地址
+ buff.append("0008");//读取目标寄存器的数量
+ NettyUtils.writeToClient(null,buff.toString(),ctx.channel(),"读取设备状态");
+ }
+
+ log.info("心跳内容" + content);
+ String bt1=content.substring(16,18);
+ String bt2=content.substring(18,20);
+ String bt3=content.substring(20,22);
+ String bt4=content.substring(22,24);
+
+
+
+// if("01".equals(bt1)){
+// ClickButton(redisUtils,content,ip,NettyUtils.button_1,NettyUtils.light_1);
+// }
+// if("01".equals(bt2)){
+// ClickButton(redisUtils,content,ip,NettyUtils.button_2,NettyUtils.light_2);
+// }
+// if("01".equals(bt3)){
+// ClickButton(redisUtils,content,ip,NettyUtils.button_3,NettyUtils.light_3);
+// }
+// if("01".equals(bt4)){
+// ClickButton(redisUtils,content,ip,NettyUtils.button_4,NettyUtils.light_4);
+// }
+
+ } else{
+ log.info("其他消息内容" + content);
+ }
+
+ }
+
+
+// public void ClickButton(RedisUtils redisUtils,String content,String ip,String ButtonCode,String LightCode){
+// log.info(ButtonCode+"按钮 被按下");
+// //读取bt_key
+// String bt_key="TCP"+ip+ButtonCode;
+// if ((Boolean) redisUtils.get(bt_key,false)) {
+// log.error("{}正在执行...",bt_key);
+// return;
+// }
+// //写入key 为Tue
+// redisUtils.set(bt_key,true,120);
+// //加载操作数据库
+// LampLogRepository lampLogRepository = SpringContextHolder.getBean(LampLogRepository.class);
+// LampLogServiceImpl bean = SpringContextHolder.getBean(LampLogServiceImpl.class);
+// BoxRepository bean1 = SpringContextHolder.getBean(BoxRepository.class);
+// //插入日志
+// LampLog lampLog = new LampLog();
+// lampLog.setIp(ip);//插入ip
+// lampLog.setButtonCode(ButtonCode);
+// lampLog.setRequestContent(content);
+// lampLog.setReturnState(ButtonCode+"被按下");
+// //获取盒子号
+// log.info("ButtonBoxCode:"+ip + ButtonCode+"====");
+// Object buttonBoxCode = redisUtils.hget("ButtonBoxCode", ip + ButtonCode,"")+"";
+// if ("".equals(buttonBoxCode)){
+// log.info("ButtonBoxCode为空:"+ip + ButtonCode+"====");
+// List boxAllData = bean1.getBoxAllData();
+// for (Box box:boxAllData){
+// redisUtils.hset("ButtonBoxCode",box.getIP()+box.getLampCode(),box.getCode(),60);
+// }
+// lampLog.setButtonBox(redisUtils.hget("ButtonBoxCode", ip + ButtonCode,"")+"");
+// log.info("ButtonBoxCode重新从redis获取:"+ip + ButtonCode+"====lampLog"+lampLog.getButtonBox()+"是否正确");
+// }else {
+// log.info("ButtonBoxCode不为空:"+buttonBoxCode.toString()+"====");
+// lampLog.setButtonBox(buttonBoxCode.toString());
+// }
+// lampLog.setOperationType("自动");
+// //插入日志
+// LampLog save = lampLogRepository.save(lampLog);
+// //先亮灯
+// NettyUtils.light_on(ip,LightCode,save.getId());
+// bean1.updateBoxLampStatus(ip,ButtonCode,"1");
+// //处理业务
+// String boxCode=lampLog.getButtonBox();
+// if(boxCode!=null&&!boxCode.equals("")) {
+// this.buttonService(boxCode);//按钮3的业务处理
+// }
+// save.setReturnContent((String) redisUtils.get(String.valueOf(save.getId())));
+// //修改日志
+// bean.update(save);
+// //释放按钮 修改Key为False
+// redisUtils.del(String.valueOf(save.getId()));
+// NettyUtils.button_off(ip,ButtonCode,save.getId());
+// redisUtils.set(bt_key,false);
+//
+// }
+
+
+ /**
+ * 设备下线处理
+ *
+ * @param ctx
+ */
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) {
+
+ String ip =((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress();
+
+ clients.remove(ctx.channel());
+ log.info("设备下线了:{}", ip);
+ }
+
+ /**
+ * 设备连接异常处理
+ *
+ * @param ctx
+ * @param cause
+ */
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ // 打印异常
+ log.info("异常:{}", cause.getMessage());
+ // 关闭连接
+ ctx.close();
+ clients.remove(ctx.channel());
+ }
+
+ //按钮1 的业务
+ public ResponseEntity buttonService(String buttonBoxCode){
+ log.info("WMS按钮"+buttonBoxCode+"的业务......");
+ BoxServiceImpl bsi = SpringContextHolder.getBean(BoxServiceImpl.class);
+ BoxMapper bm= SpringContextHolder.getBean(BoxMapper.class);
+ BoxQueryCriteria bqc=new BoxQueryCriteria();
+ bqc.setCode(buttonBoxCode);
+ List bds=bsi.queryAll(bqc);
+ if(bds.size()>0){
+ BoxDto b=bds.get(0);
+ try {
+ log.info("进来WMS按钮的业务......");
+// bsi.callBox(b);
+ } catch (Exception e) {
+ Log log_data=new Log();
+ log_data.setRequestIp(b.getIP());
+ log_data.setUsername("按钮盒设备:"+b.getLampCode());
+ log_data.setDescription("按钮盒设备业务处理");
+ log_data.setLogType("ERROR");
+ log_data.setReturnData(e.getMessage());
+ LogServiceImpl lsi = SpringContextHolder.getBean(LogServiceImpl.class);
+ lsi.saveLog(log_data);
+ log.error("灯日志"+e.getMessage());
+ Box box=bm.toEntity(b);
+ box.setLampStatus("0");
+ bsi.update(box);
+ return new ResponseEntity<>(ApiResult.success(BAD_REQUEST.value(), e.getMessage(), ""), HttpStatus.BAD_REQUEST);
+ }
+ return new ResponseEntity<>(ApiResult.success(OK.value(), "呼叫成功!", ""), HttpStatus.OK);
+ }else{
+ return new ResponseEntity<>(ApiResult.success(BAD_REQUEST.value(), "找不到对应的按钮数据", ""), HttpStatus.BAD_REQUEST);
+ }
+ }
+
+}
+
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/ReturnJson/RLocLayout.java b/youchain-system/src/main/java/com/youchain/appupdate/ReturnJson/RLocLayout.java
new file mode 100644
index 0000000..aa0f4a5
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/ReturnJson/RLocLayout.java
@@ -0,0 +1,27 @@
+package com.youchain.appupdate.ReturnJson;
+
+import lombok.Data;
+
+@Data
+public class RLocLayout {
+ String id;
+// /**行*/
+// int gRow;
+// /**列*/
+// int gCol;
+ /**类型0空,1满车,2未启用*/
+ int type;
+ /**代码*/
+ String code;
+ /**物料类型*/
+ String itemType;
+
+ /**物料*/
+ String itemName;
+
+ double x;
+
+ double y;
+
+
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/domain/SysAppUpdate.java b/youchain-system/src/main/java/com/youchain/appupdate/domain/SysAppUpdate.java
new file mode 100644
index 0000000..462322c
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/domain/SysAppUpdate.java
@@ -0,0 +1,82 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.appupdate.domain;
+
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author liuxue
+* @date 2023-07-17
+**/
+@Entity
+@Data
+@Table(name="sys_app_update")
+public class SysAppUpdate implements Serializable {
+
+ @Id
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id=0;
+
+
+ @Column(name = "`app_name`")
+ @ApiModelProperty(value = "项目名称")
+ private String appName;
+
+
+ @Column(name = "`update_status`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "更新状态:0表示不更新,1表示版本更新,不需要强制升级,2表示版本更新和强制升级。")
+ private Integer updateStatus;
+
+ @Column(name = "`version_code`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "版本代码:版本编号,自递增.用来比较这个版本是否是最新的版本.")
+ private Integer versionCode;
+
+ @Column(name = "`version_name`")
+ @ApiModelProperty(value = "版本名称:显示版本名称.")
+ private String versionName;
+
+ @Column(name = "`modify_content`")
+ @ApiModelProperty(value = "修改内容:版本更新的内容。")
+ private String modifyContent;
+
+ @Column(name = "`download_url`")
+ @ApiModelProperty(value = "下载网站:下载应用程序APK文件的地址。")
+ private String downloadUrl;
+
+ @Column(name = "`apk_size`")
+ @ApiModelProperty(value = "程序大小:应用程序APK文件的文件大小,单位为kb。")
+ private Integer apkSize;
+
+ @Column(name = "`apk_md5`")
+ @ApiModelProperty(value = "APKMD5:应用APK文件的MD5值。如果没有,则不能保证APK是完整的,每次都将再次下载。框架默认情况下使用MD5加密。")
+ private String apkMd5;
+
+ public void copy(SysAppUpdate source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/BindOrder.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/BindOrder.java
new file mode 100644
index 0000000..79e74ad
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/BindOrder.java
@@ -0,0 +1,28 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 绑定工单号的入参
+ */
+@Data
+public class BindOrder {
+ @ApiModelProperty(value = "按钮盒ID")
+ long boxId;//按钮盒ID
+
+ @ApiModelProperty(value = "物料编号")
+ String itemCode;//物料
+
+ @ApiModelProperty(value = "工单号")
+ String orderNumber;//工单号
+
+ public BindOrder(long boxId,String itemCode, String orderNumber) {
+ this.boxId = boxId;
+ this.orderNumber = orderNumber;
+ this.itemCode = itemCode;
+ }
+
+ public BindOrder() {
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/CallBox.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/CallBox.java
new file mode 100644
index 0000000..51cfb68
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/CallBox.java
@@ -0,0 +1,12 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+/**
+ * 按钮盒呼叫的入参
+ */
+@Data
+public class CallBox {
+ @ApiModelProperty(value = "按钮盒ID")
+ long id;//id
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/ContainerIn.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/ContainerIn.java
new file mode 100644
index 0000000..1b347fe
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/ContainerIn.java
@@ -0,0 +1,24 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 容器入场
+ */
+@Data
+public class ContainerIn {
+
+ @ApiModelProperty(value = "容器编号")
+ String containerCode;
+
+ @ApiModelProperty(value = "点位编号")
+ String position;
+
+ @ApiModelProperty(value = "物料编号")
+ String itemCode;
+
+ @ApiModelProperty(value = "检索码")
+ int checkCode=0;
+
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/FullStockIn.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/FullStockIn.java
new file mode 100644
index 0000000..0eb7119
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/FullStockIn.java
@@ -0,0 +1,41 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 满车入库
+ */
+@Data
+public class FullStockIn {
+ @ApiModelProperty(value = "点位编码")
+ String pointCode;
+
+ @ApiModelProperty(value = "物料编号")
+ String itemCode;
+
+ @ApiModelProperty(value = "容器码")
+ String stockCode;
+
+ @ApiModelProperty(value = "按钮盒")
+ Long boxId=0l;
+
+ @ApiModelProperty(value = "作业场景")
+ String agvScene;
+
+ @ApiModelProperty(value = "检索码")
+ int checkCode=0;
+
+
+ public FullStockIn(String pointCode, String itemCode, String stockCode, Long boxId,String agvScene,int checkCode) {
+ this.pointCode = pointCode;
+ this.stockCode = stockCode;
+ this.itemCode = itemCode;
+ this.boxId=boxId;
+ this.agvScene = agvScene;
+ this.checkCode=checkCode;
+ }
+
+ public FullStockIn() {
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/FullStockOut.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/FullStockOut.java
new file mode 100644
index 0000000..18fb747
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/FullStockOut.java
@@ -0,0 +1,33 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 满车出库
+ */
+@Data
+public class FullStockOut {
+
+ @ApiModelProperty(value = "物料编号")
+ String itemCode;
+
+ @ApiModelProperty(value = "点位编码")
+ String pointCode;
+
+ @ApiModelProperty(value = "作业场景")
+ String agvScene;
+
+ @ApiModelProperty(value = "检索码")
+ int checkCode=0;
+
+ public FullStockOut(String itemCode,String pointCode, String agvScene,int checkCode) {
+ this.pointCode = pointCode;
+ this.itemCode = itemCode;
+ this.agvScene = agvScene;
+ this.checkCode=checkCode;
+ }
+
+ public FullStockOut() {
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/LineScanStock.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/LineScanStock.java
new file mode 100644
index 0000000..0d6f494
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/LineScanStock.java
@@ -0,0 +1,13 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class LineScanStock {
+ @ApiModelProperty(value = "容器编号")
+ String stockCode;
+
+ @ApiModelProperty(value = "任务编号")
+ String taskCode;
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/MissionStateCallback.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/MissionStateCallback.java
new file mode 100644
index 0000000..8853980
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/MissionStateCallback.java
@@ -0,0 +1,19 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * KMReS接口回调的入参
+ */
+@Data
+public class MissionStateCallback {
+ @ApiModelProperty(value = "任务ID")
+ int missionCode;
+
+ @ApiModelProperty(value = "容器编号")
+ String containerCode;
+
+ @ApiModelProperty(value = "作业当前状态")
+ String missionStatus;
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/Mo.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/Mo.java
new file mode 100644
index 0000000..bf8ce98
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/Mo.java
@@ -0,0 +1,16 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 绑定Mo票入参
+ */
+@Data
+public class Mo {
+ @ApiModelProperty(value = "Mo票")
+ String mo;
+
+ @ApiModelProperty(value = "料箱号")
+ String stockCode;
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/PointCallStock.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/PointCallStock.java
new file mode 100644
index 0000000..2166196
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/PointCallStock.java
@@ -0,0 +1,17 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 扫描物料接口
+ * 入参
+ */
+@Data
+public class PointCallStock {
+ @ApiModelProperty(value = "点位编码")
+ String pointCode;
+ @ApiModelProperty(value = "AGV场景")
+ String agvScene;
+
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/ScanItemCode.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/ScanItemCode.java
new file mode 100644
index 0000000..258eb17
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/ScanItemCode.java
@@ -0,0 +1,16 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 扫描物料接口
+ * 入参
+ */
+@Data
+public class ScanItemCode {
+ @ApiModelProperty(value = "物料编号")
+ String itemCode;
+ @ApiModelProperty(value = "库位编号")
+ String pointCode;
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/inputJson/SmallCallStock.java b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/SmallCallStock.java
new file mode 100644
index 0000000..6a19fe6
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/inputJson/SmallCallStock.java
@@ -0,0 +1,20 @@
+package com.youchain.appupdate.inputJson;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 小件-满料出库入参
+ */
+@Data
+public class SmallCallStock {
+
+ @ApiModelProperty(value = "按钮盒ID")
+ long id;//id
+
+ @ApiModelProperty(value = "物料编号")
+ String itemCode;
+
+ @ApiModelProperty(value = "箱数")
+ int quantity;
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/repository/SysAppUpdateRepository.java b/youchain-system/src/main/java/com/youchain/appupdate/repository/SysAppUpdateRepository.java
new file mode 100644
index 0000000..0122f55
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/repository/SysAppUpdateRepository.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.youchain.appupdate.repository;
+
+import com.youchain.appupdate.domain.SysAppUpdate;
+import com.youchain.basicdata.domain.Box;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+/**
+* @website https://eladmin.vip
+* @author liuxue
+* @date 2023-07-17
+**/
+public interface SysAppUpdateRepository extends JpaRepository, JpaSpecificationExecutor {
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/rest/ScreenMdController.java b/youchain-system/src/main/java/com/youchain/appupdate/rest/ScreenMdController.java
new file mode 100644
index 0000000..bf9c88e
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/rest/ScreenMdController.java
@@ -0,0 +1,166 @@
+package com.youchain.appupdate.rest;
+
+import cn.hutool.json.JSONArray;
+import com.youchain.annotation.AnonymousAccess;
+import com.youchain.annotation.Log;
+import com.youchain.businessdata.service.impl.*;
+import com.youchain.report_data.utils.PieChart;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.icepear.echarts.Option;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.List;
+
+
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "美的大屏数据显示")
+@RequestMapping("/api/screenMdView")
+@Slf4j
+public class ScreenMdController {
+ private final ScreenMdServiceImpl screenMdImpl;
+ @PostMapping(value="/locLayout")
+ @Log("库位布局")
+ @ApiOperation("库位布局")
+ @AnonymousAccess
+ public ResponseEntity locLayout(String zoneType) {
+ //0空1满2禁用3空车区满
+ if(zoneType==null){
+ zoneType="MD";
+ }
+ List xys=screenMdImpl.getLocXy(zoneType);
+ List objs=screenMdImpl.queryLayout(zoneType);
+ HashMap map=new HashMap();
+ map.put("mg_top",2);
+ map.put("mg_left",1);
+ HashMap seatList=new HashMap();
+ int type0=0;
+ int type1=0;
+ int type2=0;
+ int type3=0;
+ if(objs.size()>0){
+ JSONArray seat=new JSONArray();
+ Object[] xy=xys.get(0);
+ HashMap itemTypes=new HashMap();
+ for(Object[] obj:objs){
+ double minX=Double.parseDouble(xy[0].toString());
+ double minY=Double.parseDouble(xy[1].toString());
+ double maxX=Double.parseDouble(xy[2].toString());
+ double maxY=Double.parseDouble(xy[3].toString());
+ HashMap d=new HashMap();
+ Object id=obj[0];
+ Object code=obj[1];
+ double gRow=Double.parseDouble(obj[2].toString());
+ double gCol=Double.parseDouble(obj[3].toString());
+ Object barCode=obj[4];
+ Object lot=obj[5];
+ Object disabled=obj[6];
+ String inv_status=obj[7]==null?"":obj[7].toString();
+ Object loc_status=obj[8];
+ String type="4";//1禁用,2满料,3AGV未送物料占用,4 空闲,5空车占用
+ //禁用(红色,白×),有物料(绿,白车),4,空(紫,百空),空占用(紫,橙空)
+ if(disabled.toString().equals("true")){
+ type="1";
+ }else if(loc_status.equals("OCCUPY")&&inv_status.equals("OPEN")){
+ type="2";
+ }else if(loc_status.equals("OCCUPY")&&inv_status.equals("ZY")){
+ type="3";
+ }else if(loc_status.equals("FREE")&&inv_status.equals("")){
+ type="4";
+ }else if(loc_status.equals("OCCUPY")&&inv_status.equals("")){
+ type="5";
+ }
+ d.put("id", obj[0]+"");
+// d.put("gRow",Math.abs((int)Math.ceil(gCol-maxY)));
+// d.put("gCol",(int)Math.ceil(gRow-minX));
+ //库位靠左考上显示
+ gRow=gRow-minX;
+ gCol=gCol-minY;
+ //重新计算最大最小XY
+ maxX=maxX-minX;
+ minX=0d;
+ maxY=maxY-minY;
+ minY=0;
+
+ double gRow2=gCol;
+ double gCol2=gRow;
+
+ double maxX2=maxY;
+ double maxY2 =maxX;
+
+
+ d.put("gRow",Math.abs(gRow2-maxX2));
+ d.put("gCol",gCol2);
+ d.put("type", type);
+ d.put("lot", lot);
+ d.put("code", code);
+ d.put("item_code", barCode);
+ seat.add(d);
+ }
+ String movieName="重庆美的点位布局图";
+ map.put("movieName",movieName);//+mes);
+ map.put("seatList",seat);
+ }
+ return new ResponseEntity(map, HttpStatus.OK);
+ }
+
+ @PostMapping(value="/locTypePie")
+ @Log("库位比列")
+ @ApiOperation("库位比列")
+ @AnonymousAccess
+ public ResponseEntity locTypePie(String type) {
+ //1禁用,2满料,3AGV未送物料占用,4 空闲,5空车占用
+ DecimalFormat df = new DecimalFormat("#.0");
+ int locCount=screenMdImpl.getLocCount(type);
+ int sjCount=screenMdImpl.getLocStatusCount(type);
+ String color0="#ededed";
+ String color1="#FF0000";
+ String scoreName="SCORE";
+ double percentage=sjCount*100*0.1*10/locCount;
+// percentage=Math.round(percentage);
+ percentage=Double.parseDouble(df.format(percentage));
+ if(type.equals("1")){
+// color0="#04CDE6";
+ color1="#0CC8E6";
+ color1="#021334FF";
+ }else if(type.equals("2")){
+// color0="#73E239";
+ color1="#35B45E";
+ color1="#021334FF";
+ }else if(type.equals("3")){
+// color0="#FEBA6B";
+ color1="#F29961";
+ color1="#021334FF";
+ }else if(type.equals("4")){
+// color0="#E15E68";
+ color1="#E53240";
+ color1="#021334FF";
+ }else if(type.equals("5")){
+// color0="#A682E6";
+ color1="#6244E6";
+ color1="#021334FF";
+ }
+ Option option= PieChart.pieStyle(color0,color1,scoreName,percentage);
+ return new ResponseEntity(option, HttpStatus.OK);
+ }
+
+ @PostMapping(value="/locTypePieQty")
+ @Log("库位比列数量")
+ @ApiOperation("库位比列数量")
+ @AnonymousAccess
+ public ResponseEntity locTypePieQty(String type) {
+ int sjCount=screenMdImpl.getLocStatusCount(type);
+ HashMap map=new HashMap();
+ map.put("data",sjCount);
+ return new ResponseEntity(map, HttpStatus.OK);
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/rest/SysAppUpdateController.java b/youchain-system/src/main/java/com/youchain/appupdate/rest/SysAppUpdateController.java
new file mode 100644
index 0000000..30b709c
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/rest/SysAppUpdateController.java
@@ -0,0 +1,131 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.appupdate.rest;
+
+import com.youchain.Netty.NettyUtils;
+import com.youchain.Netty.ServerListenerHandler;
+import com.youchain.annotation.Log;
+import com.youchain.annotation.rest.AnonymousGetMapping;
+import com.youchain.appupdate.domain.SysAppUpdate;
+import com.youchain.appupdate.service.SysAppUpdateService;
+import com.youchain.appupdate.service.dto.SysAppUpdateQueryCriteria;
+import com.youchain.appupdate.service.dto.SysNewAppUpdateDto;
+import io.netty.channel.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Pageable;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import io.swagger.annotations.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+* @website https://eladmin.vip
+* @author liuxue
+* @date 2023-07-17
+**/
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@Api(tags = "app_update管理")
+@RequestMapping("/api/sysAppUpdate")
+public class SysAppUpdateController {
+
+ private final SysAppUpdateService sysAppUpdateService;
+
+
+ @Log("导出数据")
+ @ApiOperation("导出数据")
+ @GetMapping(value = "/download")
+ @PreAuthorize("@el.check('sysAppUpdate:list')")
+ public void exportSysAppUpdate(HttpServletResponse response, SysAppUpdateQueryCriteria criteria) throws Exception {
+ sysAppUpdateService.download(sysAppUpdateService.queryAll(criteria), response);
+ }
+
+ @GetMapping
+ @Log("查询app_update")
+ @ApiOperation("查询app_update")
+ @PreAuthorize("@el.check('sysAppUpdate:list')")
+ public ResponseEntity querySysAppUpdate(SysAppUpdateQueryCriteria criteria, Pageable pageable){
+
+ return new ResponseEntity<>(sysAppUpdateService.queryAll(criteria,pageable),HttpStatus.OK);
+ }
+
+
+ @Log("获取最新版本")
+ @ApiOperation("获取最新版本tdshfdisuhfosihfosi093t")
+ @AnonymousGetMapping(value = "/new")
+ public ResponseEntity querySysNewAppUpdate(SysAppUpdateQueryCriteria criteria, Pageable pageable){
+
+ log.error(criteria.getBaseurl());
+ List list= sysAppUpdateService.queryByname(criteria);
+ if(list.size()>0){
+ SysNewAppUpdateDto so=list.get(list.size()-1);
+
+ String url=so.getDownloadUrl();
+ so.setCode("0");
+ so.setUpdateStatus(1);
+ so.setDownloadUrl(criteria.getBaseurl()+url);
+ return new ResponseEntity<>(so,HttpStatus.OK);
+ }
+
+ return new ResponseEntity<>("",HttpStatus.OK);
+ }
+
+
+ @PostMapping
+ @ApiOperation("上传文件")
+ @PreAuthorize("@el.check('sysAppUpdate:add')")
+ public ResponseEntity createSysAppUpdate(@RequestParam String appName,@RequestParam int versionCode,@RequestParam String versionName,@RequestParam String modifyContent, @RequestParam("file") MultipartFile file){
+
+ return new ResponseEntity<>(sysAppUpdateService.create(appName,versionCode,versionName,modifyContent,file),HttpStatus.CREATED);
+
+ }
+
+
+
+ @PutMapping
+ @Log("修改app_update")
+ @ApiOperation("修改app_update")
+ @PreAuthorize("@el.check('sysAppUpdate:edit')")
+ public ResponseEntity updateSysAppUpdate(@Validated @RequestBody SysAppUpdate resources){
+ sysAppUpdateService.update(resources);
+
+ for (Channel client : ServerListenerHandler.clients) {
+ String devce_ip =((InetSocketAddress)client.remoteAddress()).getAddress().getHostAddress();
+ NettyUtils.light_on(devce_ip,NettyUtils.light_1,null);
+ }
+
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+
+ @DeleteMapping
+ @Log("删除app_update")
+ @ApiOperation("删除app_update")
+ @PreAuthorize("@el.check('sysAppUpdate:del')")
+ public ResponseEntity deleteSysAppUpdate(@RequestBody Integer[] ids) {
+ sysAppUpdateService.deleteAll(ids);
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/SysAppUpdateService.java b/youchain-system/src/main/java/com/youchain/appupdate/service/SysAppUpdateService.java
new file mode 100644
index 0000000..8bb29a5
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/service/SysAppUpdateService.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.youchain.appupdate.service;
+
+import com.youchain.appupdate.domain.SysAppUpdate;
+import com.youchain.appupdate.service.dto.SysAppUpdateDto;
+import com.youchain.appupdate.service.dto.SysAppUpdateQueryCriteria;
+import com.youchain.appupdate.service.dto.SysNewAppUpdateDto;
+import org.springframework.data.domain.Pageable;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Map;
+import java.util.List;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+* @website https://eladmin.vip
+* @description 服务接口
+* @author liuxue
+* @date 2023-07-17
+**/
+public interface SysAppUpdateService {
+
+ /**
+ * 查询数据分页
+ * @param criteria 条件
+ * @param pageable 分页参数
+ * @return Map
+ */
+ Map queryAll(SysAppUpdateQueryCriteria criteria, Pageable pageable);
+
+ /**
+ * 查询所有数据不分页
+ * @param criteria 条件参数
+ * @return List
+ */
+ List queryAll(SysAppUpdateQueryCriteria criteria);
+
+ List queryByname(SysAppUpdateQueryCriteria criteria);
+
+ /**
+ * 根据ID查询
+ * @param id ID
+ * @return SysAppUpdateDto
+ */
+ SysAppUpdateDto findById(Integer id);
+
+
+
+ SysAppUpdateDto create( String appName,int versionCode, String versionName, String modifyContent, MultipartFile file);
+
+ /**
+ * 编辑
+ * @param resources /
+ */
+ void update(SysAppUpdate resources);
+
+ /**
+ * 多选删除
+ * @param ids /
+ */
+ void deleteAll(Integer[] ids);
+
+ /**
+ * 导出数据
+ * @param all 待导出的数据
+ * @param response /
+ * @throws Exception /
+ */
+ void download(List all, HttpServletResponse response) throws Exception, Exception;
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysAppUpdateDto.java b/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysAppUpdateDto.java
new file mode 100644
index 0000000..282e79f
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysAppUpdateDto.java
@@ -0,0 +1,54 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.appupdate.service.dto;
+
+import lombok.Data;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author liuxue
+* @date 2023-07-17
+**/
+@Data
+public class SysAppUpdateDto implements Serializable {
+
+ private Integer id;
+
+ /** 项目名称 */
+ private String appName;
+ /** 更新状态:0表示不更新,1表示版本更新,不需要强制升级,2表示版本更新和强制升级。 */
+ private Integer updateStatus;
+
+ /** 版本代码:版本编号,自递增.用来比较这个版本是否是最新的版本. */
+ private Integer versionCode;
+
+ /** 版本名称:显示版本名称. */
+ private String versionName;
+
+ /** 修改内容:版本更新的内容。 */
+ private String modifyContent;
+
+ /** 下载网站:下载应用程序APK文件的地址。 */
+ private String downloadUrl;
+
+ /** 程序大小:应用程序APK文件的文件大小,单位为kb。 */
+ private Integer apkSize;
+
+ /** APKMD5:应用APK文件的MD5值。如果没有,则不能保证APK是完整的,每次都将再次下载。框架默认情况下使用MD5加密。 */
+ private String apkMd5;
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysAppUpdateQueryCriteria.java b/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysAppUpdateQueryCriteria.java
new file mode 100644
index 0000000..4ff4f50
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysAppUpdateQueryCriteria.java
@@ -0,0 +1,34 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.appupdate.service.dto;
+
+
+import lombok.Data;
+import java.util.List;
+import com.youchain.annotation.Query;
+
+/**
+ * @website https://eladmin.vip
+ * @author liuxue
+ * @date 2023-07-18
+ **/
+@Data
+public class SysAppUpdateQueryCriteria{
+ @Query(type = Query.Type.EQUAL)
+ private String appName;
+
+ private String baseurl;
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysNewAppUpdateDto.java b/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysNewAppUpdateDto.java
new file mode 100644
index 0000000..a7b0f9c
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/service/dto/SysNewAppUpdateDto.java
@@ -0,0 +1,57 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.appupdate.service.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author liuxue
+* @date 2023-07-17
+**/
+@Data
+public class SysNewAppUpdateDto implements Serializable {
+
+ private String Code;
+
+ private String Msg;
+
+ /** 项目名称 */
+ private String appName;
+ /** 更新状态:0表示不更新,1表示版本更新,不需要强制升级,2表示版本更新和强制升级。 */
+ private Integer updateStatus;
+
+ /** 版本代码:版本编号,自递增.用来比较这个版本是否是最新的版本. */
+ private Integer versionCode;
+
+ /** 版本名称:显示版本名称. */
+ private String versionName;
+
+ /** 修改内容:版本更新的内容。 */
+ private String modifyContent;
+
+ /** 下载网站:下载应用程序APK文件的地址。 */
+ private String downloadUrl;
+
+ /** 程序大小:应用程序APK文件的文件大小,单位为kb。 */
+ private Integer apkSize;
+
+ /** APKMD5:应用APK文件的MD5值。如果没有,则不能保证APK是完整的,每次都将再次下载。框架默认情况下使用MD5加密。 */
+ private String apkMd5;
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/impl/SysAppUpdateServiceImpl.java b/youchain-system/src/main/java/com/youchain/appupdate/service/impl/SysAppUpdateServiceImpl.java
new file mode 100644
index 0000000..d901554
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/service/impl/SysAppUpdateServiceImpl.java
@@ -0,0 +1,152 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.appupdate.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.youchain.appupdate.domain.SysAppUpdate;
+import com.youchain.appupdate.service.dto.SysNewAppUpdateDto;
+import com.youchain.appupdate.service.mapstruct.SysNewAppUpdateMapper;
+import com.youchain.config.FileProperties;
+import com.youchain.exception.BadRequestException;
+import com.youchain.utils.*;
+import lombok.RequiredArgsConstructor;
+import com.youchain.appupdate.repository.SysAppUpdateRepository;
+import com.youchain.appupdate.service.SysAppUpdateService;
+import com.youchain.appupdate.service.dto.SysAppUpdateDto;
+import com.youchain.appupdate.service.dto.SysAppUpdateQueryCriteria;
+import com.youchain.appupdate.service.mapstruct.SysAppUpdateMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+
+/**
+* @website https://eladmin.vip
+* @description 服务实现
+* @author liuxue
+* @date 2023-07-17
+**/
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class SysAppUpdateServiceImpl implements SysAppUpdateService {
+
+ private final SysAppUpdateRepository sysAppUpdateRepository;
+ private final SysAppUpdateMapper sysAppUpdateMapper;
+ private final SysNewAppUpdateMapper sysNewAppUpdateMapper;
+ private final FileProperties properties;
+ @Override
+ public Map queryAll(SysAppUpdateQueryCriteria criteria, Pageable pageable){
+ Page page = sysAppUpdateRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
+ for (SysAppUpdate bean:page ) {
+ log.info(""+bean.getAppName());
+ }
+
+ return PageUtil.toPage(page.map(sysAppUpdateMapper::toDto));
+ }
+
+ @Override
+ public List queryAll(SysAppUpdateQueryCriteria criteria){
+ return sysAppUpdateMapper.toDto(sysAppUpdateRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
+ }
+
+
+ @Override
+ public List queryByname(SysAppUpdateQueryCriteria criteria){
+ return sysNewAppUpdateMapper.toDto(sysAppUpdateRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
+ }
+
+ @Override
+ @Transactional
+ public SysAppUpdateDto findById(Integer id) {
+ SysAppUpdate sysAppUpdate = sysAppUpdateRepository.findById(id).orElseGet(SysAppUpdate::new);
+ ValidationUtil.isNull(sysAppUpdate.getId(),"SysAppUpdate","id",id);
+ return sysAppUpdateMapper.toDto(sysAppUpdate);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public SysAppUpdateDto create(String appName,int versionCode, String versionName, String modifyContent, MultipartFile multipartFile) {
+
+ FileUtil.checkSize(properties.getMaxSize(), multipartFile.getSize());
+ String suffix = FileUtil.getExtensionName(multipartFile.getOriginalFilename());
+ String type = FileUtil.getFileType(suffix);
+ File file = FileUtil.upload(multipartFile, properties.getPath().getPath() + type + File.separator);
+ if(ObjectUtil.isNull(file)){
+ throw new BadRequestException("上传失败");
+ }
+ //name = StringUtils.isBlank(name) ? FileUtil.getFileNameNoEx(multipartFile.getOriginalFilename()) : name;
+
+
+ Long size=multipartFile.getSize()/1024;
+ SysAppUpdate resources=new SysAppUpdate();
+ resources.setAppName(appName);
+ resources.setId(0);
+ resources.setUpdateStatus(0);
+ resources.setVersionCode(versionCode);
+ resources.setVersionName(versionName);
+ resources.setModifyContent(modifyContent);
+
+ resources.setDownloadUrl("/file/"+type+"/"+file.getName());
+ resources.setApkSize(size.intValue());
+ resources.setApkMd5("");
+
+ return sysAppUpdateMapper.toDto(sysAppUpdateRepository.save(resources));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(SysAppUpdate resources) {
+ SysAppUpdate sysAppUpdate = sysAppUpdateRepository.findById(resources.getId()).orElseGet(SysAppUpdate::new);
+ ValidationUtil.isNull( sysAppUpdate.getId(),"SysAppUpdate","id",resources.getId());
+ sysAppUpdate.copy(resources);
+ sysAppUpdateRepository.save(sysAppUpdate);
+ }
+
+ @Override
+ public void deleteAll(Integer[] ids) {
+ for (Integer id : ids) {
+ sysAppUpdateRepository.deleteById(id);
+ }
+ }
+
+ @Override
+ public void download(List all, HttpServletResponse response) throws Exception {
+ List> list = new ArrayList<>();
+ for (SysAppUpdateDto sysAppUpdate : all) {
+ Map map = new LinkedHashMap<>();
+ map.put("更新状态。", sysAppUpdate.getUpdateStatus());
+ map.put("版本代码", sysAppUpdate.getVersionCode());
+ map.put("版本名称", sysAppUpdate.getVersionName());
+ map.put("修改内容", sysAppUpdate.getModifyContent());
+ map.put("下载网站", sysAppUpdate.getDownloadUrl());
+ map.put("程序大小", sysAppUpdate.getApkSize());
+ map.put("APKMD5", sysAppUpdate.getApkMd5());
+ list.add(map);
+ }
+ FileUtil.downloadExcel(list, response);
+ }
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/mapstruct/SysAppUpdateMapper.java b/youchain-system/src/main/java/com/youchain/appupdate/service/mapstruct/SysAppUpdateMapper.java
new file mode 100644
index 0000000..c51725a
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/service/mapstruct/SysAppUpdateMapper.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.youchain.appupdate.service.mapstruct;
+
+
+import com.youchain.base.BaseMapper;
+import com.youchain.appupdate.domain.SysAppUpdate;
+import com.youchain.appupdate.service.dto.SysAppUpdateDto;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * @website https://eladmin.vip
+ * @author liuxue
+ * @date 2023-07-18
+ **/
+@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysAppUpdateMapper extends BaseMapper {
+
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/mapstruct/SysNewAppUpdateMapper.java b/youchain-system/src/main/java/com/youchain/appupdate/service/mapstruct/SysNewAppUpdateMapper.java
new file mode 100644
index 0000000..3c800c6
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/appupdate/service/mapstruct/SysNewAppUpdateMapper.java
@@ -0,0 +1,34 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.appupdate.service.mapstruct;
+
+
+import com.youchain.appupdate.domain.SysAppUpdate;
+import com.youchain.appupdate.service.dto.SysAppUpdateDto;
+import com.youchain.appupdate.service.dto.SysNewAppUpdateDto;
+import com.youchain.base.BaseMapper;
+import org.mapstruct.Mapper;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * @website https://eladmin.vip
+ * @author liuxue
+ * @date 2023-07-18
+ **/
+@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysNewAppUpdateMapper extends BaseMapper {
+
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/Area.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/Area.java
new file mode 100644
index 0000000..e82c556
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/Area.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.basicdata.service.dto.PointDto;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * @author HJL
+ * @website https://eladmin.vip
+ * @description /
+ * @date 2023-08-14
+ **/
+@Entity
+@Data
+@Table(name = "base_area")
+public class Area extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ @Column(name = "`code`", nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "库区编号")
+ private String code;
+
+ @Column(name = "`name`", nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "库区名称")
+ private String name;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ @Column(name = "`enabled`", nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled;
+
+ @Column(name = "`heat`")
+ @ApiModelProperty(value = "热度值")
+ private Double heat=0d;
+
+ @Column(name = "`pos_x`")
+ @ApiModelProperty(value = "坐标X,更改成排序号")
+ private Double posX=0d;
+
+ @Column(name = "`pos_y`")
+ @ApiModelProperty(value = "坐标Y")
+ private Double posY=0d;
+
+ @OneToOne
+ @JoinColumn(name = "dept_id")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+
+ @Column(name = "`sequence_no`")
+ @ApiModelProperty(value = "序列号")
+ private String sequenceNo;
+
+ @Column(name = "`org_code`")
+ @ApiModelProperty(value = "org编号")
+ private String orgCode;
+
+ @Column(name = "`gc_code`")
+ @ApiModelProperty(value = "工厂")
+ private String gcCode;
+
+ @Column(name = "`working_station`",nullable = true)
+ @ApiModelProperty(value = "所属工位")
+ private String workingStation;
+
+// @OneToOne(mappedBy = "area")
+// @JoinColumn(name = "point_id")
+// @ApiModelProperty(value = "缓存库位")
+// private Point point;
+
+ @Column(name = "`point_id`")
+ @ApiModelProperty(value = "缓存库位ID")
+ private Long pointId;
+ @Column(name = "`point_code`")
+ @ApiModelProperty(value = "缓存库位Code")
+ private String pointCode;
+
+ @Column(name = "`bexb`")
+ @ApiModelProperty(value = "线边接收")
+ private Boolean bexb;
+
+ @Column(name = "`besh`")
+ @ApiModelProperty(value = "收货仓库")
+ private Boolean besh;
+
+ @Column(name = "`bezz`")
+ @ApiModelProperty(value = "制造库位耗用")
+ private Boolean bezz;
+
+ @Column(name = "`shdd`")
+ @ApiModelProperty(value = "收货担当")
+ private String shdd;
+
+ public void copy(Area source) {
+ BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/AutomaticPlanDetail.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/AutomaticPlanDetail.java
new file mode 100644
index 0000000..8aa7074
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/AutomaticPlanDetail.java
@@ -0,0 +1,125 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author houjianlan
+* @date 2024-04-07
+**/
+@Entity
+@Data
+@Table(name="base_automatic_plan_detail")
+public class AutomaticPlanDetail extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+ @Column(name = "`code`")
+ @ApiModelProperty(value = "流水")
+ private String code;
+ @OneToOne
+ @JoinColumn(name = "`automatic_planning_id`")
+ @ApiModelProperty(value = "铺线计划ID")
+ private AutomaticPlanning automaticPlanning;
+
+ @OneToOne
+ @JoinColumn(name = "`sh_area_id`")
+ @ApiModelProperty(value = "收货仓库")
+ private Area shArea;
+
+ @Column(name = "`fx_quantity`")
+ @ApiModelProperty(value = "辅线数量")
+ private Integer fxQuantity=0;
+
+ @Column(name = "`jh_quantity`")
+ @ApiModelProperty(value = "计划数量")
+ private Integer jhQuantity=0;
+
+ @Column(name = "`sx_quantity`")
+ @ApiModelProperty(value = "上线计划数量")
+ private Integer sxQuantity;
+ @Column(name = "`batch_num`")
+ @ApiModelProperty(value = "分批数量")
+ private Integer batchNum=0;
+
+ @Column(name = "`hy_quantity`")
+ @ApiModelProperty(value = "耗用数量")
+ private Integer hyQuantity=0;
+
+ @OneToOne
+ @JoinColumn(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库ID")
+ private Dept dept;
+
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled=Boolean.TRUE;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "备注")
+ private String description;
+
+ @Column(name = "`start_num`")
+ @ApiModelProperty(value = "开始机号")
+ private String startNum;
+
+ @Column(name = "`zd_start_num`")
+ @ApiModelProperty(value = "指定开始机号")
+ private String zdStartNum;
+
+ @Column(name = "`end_num`")
+ @ApiModelProperty(value = "截止机号")
+ private String endNum;
+
+ @Column(name = "`sc_end_num`")
+ @ApiModelProperty(value = "生产截止机号")
+ private String scEndNum;
+
+ @Column(name = "`hy_start_num`")
+ @ApiModelProperty(value = "耗用开始机号")
+ private String hyStartNum;
+
+ @Column(name = "`hy_end_num`")
+ @ApiModelProperty(value = "耗用截止机号")
+ private String hyEndNum;
+ @Column(name = "`jh_date`")
+ @ApiModelProperty(value = "计划日期")
+ private Date jhDate;
+ @Column(name = "`sh_hour`")
+ @ApiModelProperty(value = "送货小时数")
+ private Integer shHour=0;
+
+
+ public void copy(AutomaticPlanDetail source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/AutomaticPlanning.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/AutomaticPlanning.java
new file mode 100644
index 0000000..155c312
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/AutomaticPlanning.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author JiangKun
+ * @website https://eladmin.vip
+ * @description /
+ * @date 2024-01-05
+ **/
+@Entity
+@Data
+@Table(name = "base_automatic_planning")
+public class AutomaticPlanning extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @OneToOne
+ @JoinColumn(name = "`sh_area_id`")
+ @ApiModelProperty(value = "收货仓库")
+ private Area shArea;
+ @Column(name = "`code`")
+ @ApiModelProperty(value = "流水")
+ private String code;
+ @Column(name = "`status`")
+ @ApiModelProperty(value = "状态")
+ private String status;
+ @Column(name = "`fx_quantity`")
+ @ApiModelProperty(value = "铺线数量")
+ private Integer fxQuantity=0;
+
+ @Column(name = "`jh_quantity`")
+ @ApiModelProperty(value = "计划数量")
+ private Integer jhQuantity=0;
+
+ @Column(name = "`sx_quantity`")
+ @ApiModelProperty(value = "上线计划数量")
+ private Integer sxQuantity=0;
+
+ @Column(name = "`batch_num`")
+ @ApiModelProperty(value = "分批数量")
+ private Integer batchNum=0;
+
+ @Column(name = "`sh_hour`")
+ @ApiModelProperty(value = "送货小时数")
+ private Integer shHour=0;
+
+ @Column(name = "`hy_quantity`")
+ @ApiModelProperty(value = "耗用数量")
+ private Integer hyQuantity=0;
+
+ @OneToOne
+ @JoinColumn(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库ID")
+ private Dept dept;
+
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "备注")
+ private String description;
+
+ @Column(name = "`start_num`")
+ @ApiModelProperty(value = "开始机号")
+ private String startNum;
+
+ @Column(name = "`zd_start_num`")
+ @ApiModelProperty(value = "指定开始机号")
+ private String zdStartNum;
+
+ @Column(name = "`end_num`")
+ @ApiModelProperty(value = "截止机号")
+ private String endNum;
+
+ @Column(name = "`sc_end_num`")
+ @ApiModelProperty(value = "生产截止机号")
+ private String scEndNum;
+
+ @Column(name = "`hy_start_num`")
+ @ApiModelProperty(value = "耗用开始机号")
+ private String hyStartNum;
+
+ @Column(name = "`hy_end_num`")
+ @ApiModelProperty(value = "耗用截止机号")
+ private String hyEndNum;
+
+ @Column(name = "`jh_date`")
+ @ApiModelProperty(value = "计划日期")
+ private Date jhDate;
+
+ @Column(name = "`is_sx`")
+ @ApiModelProperty(value = "是否上线")
+ private Boolean isSx=Boolean.TRUE;
+
+ @Column(name = "`is_end`")
+ @ApiModelProperty(value = "按照输入end IDNO耗用")
+ private Boolean isEnd=Boolean.FALSE;
+
+
+
+ public void copy(AutomaticPlanning source) {
+ BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/BigItem.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/BigItem.java
new file mode 100644
index 0000000..dc1c3b2
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/BigItem.java
@@ -0,0 +1,84 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author baobinglin
+* @date 2023-12-29
+**/
+@Entity
+@Data
+@Table(name="base_big_item")
+public class BigItem extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @Column(name = "`code`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "完成品品番")
+ private String code;
+
+ @Column(name = "`name`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "完成形式名")
+ private String name;
+
+ @Column(name = "`models`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "机种")
+ private String models;
+
+ @Column(name = "`country`")
+ @NotBlank
+ @ApiModelProperty(value = "国别")
+ private String country;
+
+ @Column(name = "`outbound_type`")
+ @ApiModelProperty(value = "出库类型")
+ private String outboundType;
+
+ @Column(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库ID")
+ private Long deptId;
+
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "是否启用")
+ private Boolean enabled;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ public void copy(BigItem source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/BillType.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/BillType.java
new file mode 100644
index 0000000..ced434f
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/BillType.java
@@ -0,0 +1,84 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author houjianlan
+* @date 2023-08-07
+**/
+@Entity
+@Data
+@Table(name="base_bill_type")
+public class BillType extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @Column(name = "`code`")
+ @ApiModelProperty(value = "代码")
+ private String code;
+
+ @Column(name = "`name`")
+ @ApiModelProperty(value = "名称")
+ private String name;
+
+ @Column(name = "`prefix`")
+ @ApiModelProperty(value = "前缀")
+ private String prefix;
+
+
+ @OneToOne
+ @JoinColumn(name = "dept_id")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+ @Column(name = "`type`")
+ @ApiModelProperty(value = "类型")
+ private String type;
+
+ @Column(name = "`enabled`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled=true;
+
+ @Column(name = "`source_name`")
+ @ApiModelProperty(value = "来源名称")
+ private String sourceName;
+
+ @Column(name = "`source_id`")
+ @ApiModelProperty(value = "来源序号")
+ private Long sourceId;
+
+ public void copy(BillType source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/BomAccount.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/BomAccount.java
new file mode 100644
index 0000000..f8fcac8
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/BomAccount.java
@@ -0,0 +1,123 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author baobinglin
+* @date 2024-01-02
+**/
+@Entity
+@Data
+@Table(name="base_bom_account")
+public class BomAccount extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+ @OneToOne
+ @JoinColumn(name = "`big_item_id`")
+ @ApiModelProperty(value = "完成品品番")
+ private BigItem bigItem;
+ @OneToOne
+ @JoinColumn(name = "`item_id`")
+ @ApiModelProperty(value = "部品品番")
+ private Item item;
+
+ @Column(name = "`contents`")
+ @ApiModelProperty(value = "加工内容")
+ private String contents;
+
+ @Column(name = "`singles`")
+ @ApiModelProperty(value = "单用")
+ private Integer singles=0;
+
+ @OneToOne
+ @JoinColumn(name = "`r_area_id`")
+ @ApiModelProperty(value = "接收仓库")
+ private Area rArea;
+
+ @OneToOne
+ @JoinColumn(name = "`c_area_id`")
+ @ApiModelProperty(value = "出库仓库")
+ private Area cArea;
+ @Column(name = "`out_type`")
+ @ApiModelProperty(value = "出库类型")
+ private String outType;
+
+ @Column(name = "`station_type`")
+ @ApiModelProperty(value = "工位")
+ private String stationType;
+
+ @Column(name = "`bp_type`")
+ @ApiModelProperty(value = "部品种类")
+ private String bp_type;
+
+ @OneToOne
+ @JoinColumn(name = "`h_point_id`")
+ @ApiModelProperty(value = "缓存库位")
+ private Point hPoint;
+ @OneToOne
+ @JoinColumn(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库ID")
+ private Dept dept;
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ @Column(name = "`AC`")
+ @ApiModelProperty(value = "A/C")
+ private String ac;
+
+ @Column(name = "`bonded`")
+ @ApiModelProperty(value = "税别")
+ private String bonded;
+
+ @OneToOne
+ @JoinColumn(name = "`z_point_id`")
+ @ApiModelProperty(value = "制造库位")
+ private Point zPoint;
+
+ @Column(name = "`supplier`")
+ @ApiModelProperty(value = "供应商")
+ private String supplier;
+
+ @Column(name = "`pc_qty`")
+ @ApiModelProperty(value = "分批需求数")
+ private Double pcQty=0d;
+
+ public void copy(BomAccount source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/BomAccountLog.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/BomAccountLog.java
new file mode 100644
index 0000000..b7b93f8
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/BomAccountLog.java
@@ -0,0 +1,127 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author houjianlan
+* @date 2024-04-24
+**/
+@Entity
+@Data
+@Table(name="base_bom_account_log")
+public class BomAccountLog extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+ @OneToOne
+ @JoinColumn(name = "`big_item_id`")
+ @ApiModelProperty(value = "完成品品番")
+ private BigItem bigItem;
+ @OneToOne
+ @JoinColumn(name = "`item_id`")
+ @ApiModelProperty(value = "部品品番")
+ private Item item;
+
+ @Column(name = "`contents`")
+ @ApiModelProperty(value = "加工内容")
+ private String contents;
+
+ @Column(name = "`singles`")
+ @ApiModelProperty(value = "单用")
+ private Integer singles;
+
+ @OneToOne
+ @JoinColumn(name = "`r_area_id`")
+ @ApiModelProperty(value = "接受仓库")
+ private Area rArea;
+
+ @OneToOne
+ @JoinColumn(name = "`c_area_id`")
+ @ApiModelProperty(value = "出库仓库")
+ private Area cArea;
+ @Column(name = "`out_type`")
+ @ApiModelProperty(value = "出库类型")
+ private String outType;
+
+ @Column(name = "`station_type`")
+ @ApiModelProperty(value = "工位")
+ private String stationType;
+
+ @Column(name = "`bp_type`")
+ @ApiModelProperty(value = "部品种类")
+ private String bp_type;
+
+ @OneToOne
+ @JoinColumn(name = "`h_point_id`")
+ @ApiModelProperty(value = "缓存库位")
+ private Point hPoint;
+ @OneToOne
+ @JoinColumn(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库ID")
+ private Dept dept;
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled=Boolean.TRUE;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ @Column(name = "`AC`")
+ @ApiModelProperty(value = "A/C")
+ private String ac;
+
+ @Column(name = "`bonded`")
+ @ApiModelProperty(value = "税别")
+ private String bonded;
+
+ @OneToOne
+ @JoinColumn(name = "`z_point_id`")
+ @ApiModelProperty(value = "制造库位")
+ private Point zPoint;
+
+ @Column(name = "`supplier`")
+ @ApiModelProperty(value = "供应商")
+ private String supplier;
+
+ @Column(name = "`bom_account_id`")
+ @ApiModelProperty(value = "BOMID")
+ private Long bomAccountId;
+
+ @Column(name = "`oper_type`")
+ @ApiModelProperty(value = "操作类型")
+ private String operType;
+
+ public void copy(BomAccountLog source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/Box.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/Box.java
new file mode 100644
index 0000000..877ebba
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/Box.java
@@ -0,0 +1,102 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.hibernate.annotations.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author huojin
+* @date 2023-08-17
+**/
+@Entity
+@Data
+@Table(name="base_box")
+public class Box extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @Column(name = "`code`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "按钮盒编号")
+ private String code;
+
+ @Column(name = "`name`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "按钮盒名称")
+ private String name;
+
+ @OneToOne
+ @JoinColumn(name = "`item_id`",nullable = true)
+ @ApiModelProperty(value = "物料")
+ private Item item;
+
+ @OneToOne
+ @JoinColumn(name = "`point_id`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "点位")
+ private Point point;
+
+ @Column(name = "`enabled`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled=true;
+
+ @Column(name = "`order_Number`")
+ @ApiModelProperty(value = "工单号")
+ private String orderNumber;
+
+ @OneToOne
+ @JoinColumn(name = "dept_id")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+ @Column(name = "`sort`")
+ @ApiModelProperty(value = "排序")
+ private int sort=0;
+
+ @Column(name = "`IP`")
+ @ApiModelProperty(value = "IP")
+ private String iP;
+
+ @Column(name = "`lamp_status`")
+ @ApiModelProperty(value = "指示灯状态")
+ private String lampStatus;
+
+ @Column(name = "`lamp_code`")
+ @ApiModelProperty(value = "按钮盒编号")
+ private String lampCode;
+ public void copy(Box source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/DesignList.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/DesignList.java
new file mode 100644
index 0000000..38011a0
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/DesignList.java
@@ -0,0 +1,151 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import org.hibernate.annotations.CreationTimestamp;
+import org.hibernate.annotations.UpdateTimestamp;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.LastModifiedBy;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author LY
+* @date 2024-04-26
+**/
+@Entity
+@Data
+@Table(name="data_design_list")
+public class DesignList extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ @Column(name = "`no`")
+ @ApiModelProperty(value = "No")
+ private String no;
+ @Column(name = "`chase_center`")
+ @ApiModelProperty(value = "変通No.11桁")
+ private String chaseCenter;
+
+ @Column(name = "`contraposition`")
+ @ApiModelProperty(value = "设变号")
+ private String contraposition;
+
+ @Column(name = "`designation`")
+ @ApiModelProperty(value = "一括番号")
+ private String designation;
+
+ @Column(name = "`hypothesis`")
+ @ApiModelProperty(value = "关联设变")
+ private String hypothesis;
+
+ @Column(name = "`supplier_code`")
+ @ApiModelProperty(value = "供应商代码")
+ private String supplierCode;
+
+ @Column(name = "`supplier_name`")
+ @ApiModelProperty(value = "供应商名称")
+ private String supplierName;
+
+ @Column(name = "`ac`")
+ @ApiModelProperty(value = "A/C")
+ private String ac;
+
+ @Column(name = "`content`")
+ @ApiModelProperty(value = "加工内容")
+ private String content;
+
+ @Column(name = "`product_name`")
+ @ApiModelProperty(value = "品名(中文)")
+ private String productName;
+
+ @Column(name = "`use_singly`")
+ @ApiModelProperty(value = "单用")
+ private Integer useSingly;
+
+ @Column(name = "`enable`")
+ @ApiModelProperty(value = "订货要否")
+ private Boolean enable;
+
+ @Column(name = "`naso`")
+ @ApiModelProperty(value = "纳所")
+ private String naso;
+
+ @Column(name = "`monthly_output`")
+ @ApiModelProperty(value = "月产量")
+ private String monthlyOutput;
+
+ @Column(name = "`t_type_code`")
+ @ApiModelProperty(value = "T型式代码")
+ private String tTypeCode;
+
+ @Column(name = "`t_type_name`")
+ @ApiModelProperty(value = "T型式名")
+ private String tTypeName;
+
+ @Column(name = "`scrap_disposal`")
+ @ApiModelProperty(value = "旧品处理")
+ private String scrapDisposal;
+
+ @Column(name = "`implementation_date`")
+ @ApiModelProperty(value = "系统实施日")
+ private String implementationDate;
+
+ @OneToOne
+ @JoinColumn(name = "`big_item_id`")
+ @ApiModelProperty(value = "完成品品番")
+ private BigItem bigItem;
+
+ @OneToOne
+ @JoinColumn(name = "`new_item_id`")
+ @ApiModelProperty(value = "新品番")
+ private Item nitem;
+
+ @OneToOne
+ @JoinColumn(name = "`old_item_id`")
+ @ApiModelProperty(value = "旧品番")
+ private Item oitem;
+ @Column(name = "`old_item_code`")
+ @ApiModelProperty(value = "旧品番")
+ private String oldItemCode;
+ @Column(name = "`new_item_code`")
+ @ApiModelProperty(value = "新品番")
+ private String newItemCode;
+ @Column(name = "`big_item_code`")
+ @ApiModelProperty(value = "完成品番")
+ private String bigItemCode;
+
+
+
+
+
+ public void copy(DesignList source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/Item.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/Item.java
new file mode 100644
index 0000000..bda9951
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/Item.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+ * @website https://eladmin.vip
+ * @description /
+ * @author houjianlan
+ * @date 2023-08-07
+ **/
+@Entity
+@Data
+@Table(name="base_item")
+public class Item extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @Column(name = "`code`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "代码")
+ private String code;
+
+ @Column(name = "`name`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "名称")
+ private String name;
+
+ @Column(name = "`specs`")
+ @ApiModelProperty(value = "规格")
+ private String specs;
+
+ @Column(name = "`structure_id`")
+ @ApiModelProperty(value = "客户ID")
+ private Long structureId;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ @Column(name = "`is_attribute1`")
+ @ApiModelProperty(value = "是否发动机")
+ private Boolean isAttribute1=true;
+ @Column(name = "`is_attribute2`")
+ @ApiModelProperty(value = "是否预备货")
+ private Boolean isAttribute2=true;
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "是否失效")
+ private Boolean enabled=true;
+
+ @Column(name = "`valid_period`")
+ @ApiModelProperty(value = "保质期")
+ private Integer validPeriod;
+
+ @Column(name = "`alert_leading_days`")
+ @ApiModelProperty(value = "预警天数")
+ private Integer alertLeadingDays;
+
+ @Column(name = "`large_class`")
+ @ApiModelProperty(value = "大类,组合代码,自动叫料捆绑,数量一致")
+ private String largeClass;
+
+ @Column(name = "`center_class`")
+ @ApiModelProperty(value = "中类")
+ private String centerClass;
+
+ @Column(name = "`small_class`")
+ @ApiModelProperty(value = "小类")
+ private String smallClass;
+
+ @Column(name = "`good_type`")
+ @ApiModelProperty(value = "物料类型")
+ private String goodType;
+
+ @Column(name = "`length`")
+ @ApiModelProperty(value = "长")
+ private Double length=0d;
+
+ @Column(name = "`width`")
+ @ApiModelProperty(value = "宽")
+ private Double width=0d;
+
+ @Column(name = "`height`")
+ @ApiModelProperty(value = "高")
+ private Double height=0d;
+
+ @Column(name = "`weight`")
+ @ApiModelProperty(value = "重量")
+ private Double weight=0d;
+
+ @Column(name = "`volume`")
+ @ApiModelProperty(value = "体积")
+ private Double volume=0d;
+
+ @Column(name = "`unit`")
+ @ApiModelProperty(value = "单位")
+ private String unit;
+
+ @Column(name = "`master_unit`")
+ @ApiModelProperty(value = "大单位")
+ private String masterUnit;
+
+ @Column(name = "`pack_number`")
+ @ApiModelProperty(value = "包装系数")
+ private Integer packNumber=1;
+
+ @Column(name = "`bar_code`")
+ @ApiModelProperty(value = "条码")
+ private String barCode;
+
+ @OneToOne
+ @JoinColumn(name = "dept_id")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+ @Column(name = "`source_name`")
+ @ApiModelProperty(value = "来源名称")
+ private String sourceName;
+
+ @Column(name = "`source_id`")
+ @ApiModelProperty(value = "来源序号")
+ private Long sourceId;
+
+ @OneToOne
+ @JoinColumn(name = "stock_type")
+ @ApiModelProperty(value = "料箱类型")
+ private StockType stockType;
+
+ @Column(name = "`extend_d1`")
+ @ApiModelProperty(value = "默认容器装载数")
+ private Double extendD1=1d;
+
+ @Column(name = "`extend_d2`")
+ @ApiModelProperty(value = "冷却时长")
+ private Double extendD2=4d;
+
+ @Column(name = "`extend_d3`")
+ @ApiModelProperty(value = "收容数")
+ private Double extendD3=0d;
+
+ @Column(name = "`extend_d4`")
+ @ApiModelProperty(value = "扩展小数4")
+ private Double extendD4=0d;
+
+ @Column(name = "`extend_d5`")
+ @ApiModelProperty(value = "扩展小数5")
+ private Double extendD5=0d;
+
+ @Column(name = "`extend_num1`")
+ @ApiModelProperty(value = "扩展整型1")
+ private Long extendNum1;
+
+ @Column(name = "`extend_num2`")
+ @ApiModelProperty(value = "扩展整型2")
+ private Long extendNum2;
+
+ @Column(name = "`extend_num3`")
+ @ApiModelProperty(value = "扩展整型3")
+ private Long extendNum3;
+
+ @Column(name = "`extend_num4`")
+ @ApiModelProperty(value = "扩展整型4")
+ private Long extendNum4;
+
+ @Column(name = "`extend_num5`")
+ @ApiModelProperty(value = "扩展整型5")
+ private Long extendNum5;
+
+ @Column(name = "`extend_str1`")
+ @ApiModelProperty(value = "接口代码")
+ private String extendStr1;
+
+ @Column(name = "`extend_str2`")
+ @ApiModelProperty(value = "扩展字符2")
+ private String extendStr2;
+
+ @Column(name = "`extend_str3`")
+ @ApiModelProperty(value = "何姿")
+ private String extendStr3;
+
+ @Column(name = "`extend_str4`")
+ @ApiModelProperty(value = "扩展字符4")
+ private String extendStr4;
+
+ @Column(name = "`extend_str5`")
+ @ApiModelProperty(value = "扩展字符5")
+ private String extendStr5;
+ @OneToOne
+ @JoinColumn(name = "`point_id`")
+ @ApiModelProperty(value = "库位")
+ private Point point;
+
+ public void copy(Item source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/ItemLis.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/ItemLis.java
new file mode 100644
index 0000000..fcee49d
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/ItemLis.java
@@ -0,0 +1,84 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author baobinglin
+* @date 2024-01-03
+**/
+@Entity
+@Data
+@Table(name="base_item_lis")
+public class ItemLis extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @OneToOne
+ @JoinColumn(name = "`big_item_id`")
+ @ApiModelProperty(value = "完成品品番")
+ private BigItem bigItem;
+
+ @Column(name = "`out_type`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "出库类型")
+ private String outType;
+
+ @Column(name = "`bp_type`")
+ @ApiModelProperty(value = "部品种类")
+ private String bpType;
+ @OneToOne
+ @JoinColumn(name = "`r_area_id`")
+ @ApiModelProperty(value = "入库库区")
+ private Area rArea;
+
+ @OneToOne
+ @JoinColumn(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled;
+
+ @Column(name = "`station_type`")
+ @ApiModelProperty(value = "工位")
+ private String stationType;
+
+ public void copy(ItemLis source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/ItemRelation.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/ItemRelation.java
new file mode 100644
index 0000000..f90ad0a
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/ItemRelation.java
@@ -0,0 +1,89 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author baobinglin
+* @date 2024-01-04
+**/
+@Entity
+@Data
+@Table(name="base_item_relation")
+public class ItemRelation extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @Column(name = "`be_supplier`")
+ @ApiModelProperty(value = "供应商")
+ private String beSupplier;
+
+ @Column(name = "`bar_code`")
+ @ApiModelProperty(value = "key")
+ private String barCode;
+
+ @OneToOne
+ @JoinColumn(name = "`item_id`")
+ @ApiModelProperty(value = "品番")
+ private Item item;
+
+ @Column(name = "`code`")
+ @ApiModelProperty(value = "纳入场所")
+ private String code;
+
+ @Column(name = "`door`")
+ @ApiModelProperty(value = "门")
+ private String door;
+
+ @Column(name = "`type`")
+ @ApiModelProperty(value = "箱种")
+ private String type;
+
+ @Column(name = "`quantity`")
+ @ApiModelProperty(value = "收容数")
+ private Double quantity;
+
+ @Column(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库ID")
+ private Long deptId;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled;
+
+ public void copy(ItemRelation source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/Point.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/Point.java
new file mode 100644
index 0000000..ff6ed95
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/Point.java
@@ -0,0 +1,124 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author liuxue
+* @date 2023-07-26
+**/
+@Entity
+@Data
+@Table(name="base_point")
+public class Point extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ @Column(name = "`code`")
+ @ApiModelProperty(value = "RCS代码")
+ private String code;
+
+ @Column(name = "`name`")
+ @ApiModelProperty(value = "名称")
+ private String name;
+
+ @Column(name = "`status`")
+ @ApiModelProperty(value = "状态")
+ private String status;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "存储类型")
+ private String description;
+
+ @Column(name = "`beat_code`")
+ @ApiModelProperty(value = "区域编码")
+ private String beatCode;
+
+ @Column(name = "`item_code`")
+ @ApiModelProperty(value = "机械臂作业物料编码")
+ private String itemCode;
+
+ @OneToOne
+ @JoinColumn(name = "area_id")
+ @ApiModelProperty(value = "库区ID")
+ private Area area;
+
+// @OneToOne
+// @JoinColumn(name = "point_id")
+// @ApiModelProperty(value = "暂存库位")
+// private Point point;
+ @ApiModelProperty(value = "是否启用")
+ private Boolean enabled=Boolean.TRUE;
+
+ @OneToOne
+ @JoinColumn(name = "dept_id")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+ @Column(name = "`pos_x`")
+ @ApiModelProperty(value = "坐标X")
+ private Double posX=0d;
+
+ @Column(name = "`pos_y`")
+ @ApiModelProperty(value = "坐标Y")
+ private Double posY=0d;
+
+ @Column(name = "`pos_z`")
+ @ApiModelProperty(value = "坐标Z")
+ private Double posZ=0d;
+
+ @Column(name = "`type`")
+ @ApiModelProperty(value = "类型")
+ private String type;
+
+ @Column(name = "`heat`")
+ @ApiModelProperty(value = "热度")
+ private Double heat;
+
+ @Column(name = "`rows`")
+ @ApiModelProperty(value = "层")
+ private int rows=0;
+
+ @Column(name = "`col`")
+ @ApiModelProperty(value = "列")
+ private int col=0;
+
+ @Column(name = "`line`")
+ @ApiModelProperty(value = "排")
+ private int line=0;
+
+ @Column(name = "`sort_index`")
+ @ApiModelProperty(value = "排序")
+ private int sortIndex=0;
+ public void copy(Point source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/ProductionPlan.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/ProductionPlan.java
new file mode 100644
index 0000000..a8fa56b
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/ProductionPlan.java
@@ -0,0 +1,156 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author JiangKun
+* @date 2024-01-04
+**/
+@Entity
+@Data
+@Table(name="base_production_plan")
+public class ProductionPlan extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @OneToOne
+ @JoinColumn(name = "`dept_id`")
+ @ApiModelProperty(value = "仓库ID")
+ private Dept dept;
+
+ @Column(name = "`enabled`")
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled;
+
+ @OneToOne
+ @JoinColumn(name = "`big_item_id`",nullable = false)
+ @ApiModelProperty(value = "完成品番")
+ private BigItem bigItem;
+
+ @Column(name = "`working_station`",nullable = false)
+ @NotBlank
+ @ApiModelProperty(value = "工位")
+ private String workingStation;
+
+ @Column(name = "`No`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "No")
+ private Integer no;
+
+ @Column(name = "`import_date`")
+ @ApiModelProperty(value = "导入日期")
+ private Timestamp importDate;
+
+ @Column(name = "`planned_date`")
+ @ApiModelProperty(value = "计划日期")
+ private Timestamp plannedDate;
+
+ @Column(name = "`downline_date`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "下线日期")
+ private Timestamp downlineDate;
+
+ @Column(name = "`take_up_time`")
+ @ApiModelProperty(value = "耗用时间")
+ private Timestamp takeUpTime;
+
+ @Column(name = "`IDNO`")
+ @ApiModelProperty(value = "IDNO")
+ private String idno;
+
+ @Column(name = "`monthly_no`")
+ @ApiModelProperty(value = "月度序号")
+ private String monthlyNo;
+
+ @Column(name = "`project_no`")
+ @ApiModelProperty(value = "计划单号")
+ private String projectNo;
+
+ @Column(name = "`make_line`")
+ @ApiModelProperty(value = "制造线")
+ private String makeLine;
+
+ @Column(name = "`order_no`")
+ @ApiModelProperty(value = "序号")
+ private Long orderNo;
+
+ @OneToOne
+ @JoinColumn(name = "`bom_list_id`")
+ @ApiModelProperty(value = "工位清单")
+ private BomAccount bomList;
+ @OneToOne
+ @JoinColumn(name = "`sh_area_id`")
+ @ApiModelProperty(value = "收货仓库")
+ private Area shArea;
+ @OneToOne
+ @JoinColumn(name = "`rk_area_id`")
+ @ApiModelProperty(value = "入库库区")
+ private Area rkArea;
+
+ @Column(name = "`pick_plan_id`")
+ @ApiModelProperty(value = "备货计划ID")
+ private Long pickPlan;
+
+ @Column(name = "`type`")
+ @ApiModelProperty(value = "出库类型")
+ private String type;
+
+ @Column(name = "`part_variety`")
+ @ApiModelProperty(value = "部品种类")
+ private String partVariety;
+
+ @Column(name = "`statue`")
+ @ApiModelProperty(value = "耗用状态")
+ private String statue;
+ @OneToOne
+ @JoinColumn(name = "`auto_production_id`")
+ @ApiModelProperty(value = "所属自动计划")
+ private ProductionPlan autoProduction;
+
+ @Column(name = "`description`")
+ @ApiModelProperty(value = "描述")
+ private String description;
+
+ @Column(name = "`off_line_part_id`")
+ @ApiModelProperty(value = "下线零件ID")
+ private Long offLinePart;
+
+ @Column(name = "`machine_no`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "机号")
+ private String machineNo;
+
+ public void copy(ProductionPlan source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/ProductionPlanVo.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/ProductionPlanVo.java
new file mode 100644
index 0000000..123e148
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/ProductionPlanVo.java
@@ -0,0 +1,12 @@
+package com.youchain.basicdata.domain;
+
+import lombok.Data;
+
+@Data
+public class ProductionPlanVo {
+ private Long id;
+ private String machineNo;
+ private String workingStation;
+ private String name;
+ private Integer number;
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/Stock.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/Stock.java
new file mode 100644
index 0000000..95f6b83
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/Stock.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author liuxue
+* @date 2023-07-28
+**/
+@Entity
+@Data
+@Table(name="base_stock")
+public class Stock extends BaseEntity implements Serializable {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "`id`")
+ @ApiModelProperty(value = "容器ID")
+ private Long id;
+
+ @Column(name = "`code`",nullable = false)
+ @ApiModelProperty(value = "容器代码")
+ private String code;
+
+ @Column(name = "`status`")
+ @ApiModelProperty(value = "容器状态")
+ private String status;
+
+ @Column(name = "`pid`")
+ @ApiModelProperty(value = "上级容器ID")
+ private Long pid;
+
+ @OneToOne
+ @JoinColumn(name = "dept_id")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+ @OneToOne
+ @JoinColumn(name = "point_id")
+ @ApiModelProperty(value = "点位")
+ private Point point;
+
+ @Column(name = "`sub_count`")
+ @ApiModelProperty(value = "子容器数量")
+ private Integer subCount;
+
+ @Column(name = "`name`")
+ @NotBlank
+ @ApiModelProperty(value = "容器名称")
+ private String name;
+
+
+ @OneToOne
+ @JoinColumn(name = "type_id")
+ @ApiModelProperty(value = "容器类型")
+ private StockType stockType;
+
+
+ @Column(name = "`use_weight`")
+ @ApiModelProperty(value = "容器使用重量")
+ private Double useWeight;
+
+ @Column(name = "`use_size`")
+ @ApiModelProperty(value = "容器使用体积")
+ private Double useSize;
+
+ @Column(name = "`usage_weight`")
+ @ApiModelProperty(value = "容器重量占用率")
+ private Double usageWeight;
+
+ @Column(name = "`usage_size`")
+ @ApiModelProperty(value = "容器体积占用率")
+ private Double usageSize;
+
+ @ApiModelProperty(value = "是否启用")
+ private Boolean enabled;
+
+ @Column(name = "`top_id`")
+ @ApiModelProperty(value = "顶级容器ID")
+ private Long topId;
+
+ public void copy(Stock source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/StockType.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/StockType.java
new file mode 100644
index 0000000..dcf28d7
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/StockType.java
@@ -0,0 +1,86 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import com.youchain.modules.system.domain.Dept;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author liuxue
+* @date 2023-07-28
+**/
+@Entity
+@Data
+@Table(name="base_stock_type")
+public class StockType extends BaseEntity implements Serializable {
+
+ @Id
+ @Column(name = "`id`")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @ApiModelProperty(value = "ID")
+ private Long id;
+
+ @Column(name = "`name`")
+ @ApiModelProperty(value = "名称")
+ private String name;
+
+ @Column(name = "`code`")
+ @ApiModelProperty(value = "代码")
+ private String code;
+
+ @Column(name = "`enabled`",nullable = false)
+ @NotNull
+ @ApiModelProperty(value = "状态:1启用、0禁用")
+ private Boolean enabled=true;
+
+ @Column(name = "`length`")
+ @ApiModelProperty(value = "长")
+ private Double length=0d;
+
+ @Column(name = "`width`")
+ @ApiModelProperty(value = "宽")
+ private Double width=0d;
+
+ @Column(name = "`height`")
+ @ApiModelProperty(value = "高")
+ private Double height=0d;
+
+ @Column(name = "`weight`")
+ @ApiModelProperty(value = "重量")
+ private Double weight=0d;
+
+ @Column(name = "`size`")
+ @ApiModelProperty(value = "体积")
+ private Double size=0d;
+
+ @OneToOne
+ @JoinColumn(name = "dept_id")
+ @ApiModelProperty(value = "仓库")
+ private Dept dept;
+
+ public void copy(StockType source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/TableConfig.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/TableConfig.java
new file mode 100644
index 0000000..1088a5e
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/TableConfig.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.youchain.basicdata.domain;
+
+import com.youchain.base.BaseEntity;
+import lombok.Data;
+import cn.hutool.core.bean.BeanUtil;
+import io.swagger.annotations.ApiModelProperty;
+import cn.hutool.core.bean.copier.CopyOptions;
+import javax.persistence.*;
+import javax.validation.constraints.*;
+import java.sql.Timestamp;
+import java.io.Serializable;
+
+/**
+* @website https://eladmin.vip
+* @description /
+* @author LiuXue
+* @date 2023-08-28
+**/
+@Entity
+@Data
+@Table(name="base_table_config")
+public class TableConfig extends BaseEntity implements Serializable {
+
+ @Id
+ @Column(name = "`id`")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @ApiModelProperty(value = "ID")
+ private Integer id;
+
+ @Column(name = "`table_type`")
+ @ApiModelProperty(value = "tableType")
+ private String tableType;
+
+ @Column(name = "`value`")
+ @ApiModelProperty(value = "value")
+ private String value;
+
+
+
+ public void copy(TableConfig source){
+ BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
+ }
+}
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/AreaRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/AreaRepository.java
new file mode 100644
index 0000000..01c2839
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/AreaRepository.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.youchain.basicdata.repository;
+
+import com.youchain.basicdata.domain.Area;
+import com.youchain.basicdata.domain.BigItem;
+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.data.repository.query.Param;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+* @website https://eladmin.vip
+* @author HJL
+* @date 2023-08-14
+**/
+public interface AreaRepository extends JpaRepository , JpaSpecificationExecutor {
+ @Query(value = "SELECT * FROM base_area", nativeQuery = true)
+ List getAreas();
+ @Query(value = "SELECT * FROM base_area area where area.code =:code", nativeQuery = true)
+ Area getByCode(@Param("code")String code);
+
+ @Query(value = "SELECT * FROM base_area area where area.name =:name", nativeQuery = true)
+ Area getByName(@Param("name")String name);
+
+ @Query(value = "SELECT * FROM base_area area where area.code =:code or area.name=:name", nativeQuery = true)
+ Area findByCodeOrName(@Param("code")String code,@Param("name")String name);
+
+ @Query(value = "SELECT * FROM base_area area where area.code =:code and area.bexb=1", nativeQuery = true)
+ Area getJsKq(@Param("code")String code);
+
+ /**
+ * 将working_station字段设置位null
+ * @param id
+ */
+ @Modifying
+ @Transactional
+ @Query(value = "UPDATE `base_area` area SET area.working_station = NULL where id = :id", nativeQuery = true)
+ void updateWorkingStationISNull(@Param("id") Long id);
+
+ @Query(value = "SELECT * FROM base_area t where t.code in ('A仓','S仓')", nativeQuery = true)
+ List getBomOutAreas();
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/AutomaticPlanDetailRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/AutomaticPlanDetailRepository.java
new file mode 100644
index 0000000..b8751f8
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/AutomaticPlanDetailRepository.java
@@ -0,0 +1,28 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.repository;
+
+import com.youchain.basicdata.domain.AutomaticPlanDetail;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+/**
+* @website https://eladmin.vip
+* @author houjianlan
+* @date 2024-04-07
+**/
+public interface AutomaticPlanDetailRepository extends JpaRepository, JpaSpecificationExecutor {
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/AutomaticPlanningRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/AutomaticPlanningRepository.java
new file mode 100644
index 0000000..e1b1b74
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/AutomaticPlanningRepository.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.youchain.basicdata.repository;
+
+import com.youchain.basicdata.domain.AutomaticPlanning;
+import com.youchain.basicdata.domain.BomAccount;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+/**
+* @website https://eladmin.vip
+* @author JiangKun
+* @date 2024-01-05
+**/
+public interface AutomaticPlanningRepository extends JpaRepository, JpaSpecificationExecutor {
+ /**
+ * 根据 ShAreaId 查询
+ * @param sh_area_id /
+ * @return /
+ */
+ AutomaticPlanning findByShAreaId(Long sh_area_id);
+
+ @Query(value = "SELECT DATE_FORMAT(b.update_time,'%Y-%m-%d') jh_date FROM `base_automatic_planning` b where b.sh_area_id=?1 and b.is_sx=1", nativeQuery = true)
+ String queryUpdateTime(Long area_id);
+
+ @Query(value = "SELECT * FROM base_automatic_planning p where sh_area_id=?1 and p.is_sx=?2", nativeQuery = true)
+ List existSxData(Long area_id,Boolean is_sx);
+
+ @Query(value = "SELECT id FROM base_automatic_planning where sh_area_id=?1", nativeQuery = true)
+ Long Id(Long area_id);
+
+ @Query(value = "SELECT * FROM base_automatic_planning p where p.is_sx=1", nativeQuery = true)
+ List getAll();
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/BigItemRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/BigItemRepository.java
new file mode 100644
index 0000000..3a85b99
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/BigItemRepository.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.youchain.basicdata.repository;
+
+import com.youchain.basicdata.domain.BigItem;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+* @website https://eladmin.vip
+* @author baobinglin
+* @date 2023-12-29
+**/
+public interface BigItemRepository extends JpaRepository, JpaSpecificationExecutor {
+ /**
+ * 根据 Code 查询
+ * @param code /
+ * @return /
+ */
+ @Query(value = "SELECT * FROM base_big_item i where i.code=?1", nativeQuery = true)
+ BigItem findByCode(String code);
+
+ @Query(value = "SELECT * FROM base_big_item i where i.code=?1 and i.models=?2", nativeQuery = true)
+ BigItem findUnique(String code,String models);
+
+ @Query(value = "SELECT * FROM base_big_item bigItem where bigItem.code=:code and bigItem.name=:name", nativeQuery = true)
+ BigItem findByCodeName(@Param("code") String code,@Param("name") String name);
+
+ @Query(value = "SELECT * FROM base_big_item", nativeQuery = true)
+ List getBigItem();
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/BillTypeRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/BillTypeRepository.java
new file mode 100644
index 0000000..8aefcfd
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/BillTypeRepository.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.youchain.basicdata.repository;
+
+import com.youchain.basicdata.domain.BillType;
+import com.youchain.basicdata.domain.BomAccount;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+/**
+* @website https://eladmin.vip
+* @author houjianlan
+* @date 2023-08-07
+**/
+public interface BillTypeRepository extends JpaRepository, JpaSpecificationExecutor {
+
+ @Query(value = "SELECT * FROM `base_bill_type` bbt WHERE bbt.name =:name", nativeQuery = true)
+ BillType findByName(@Param("name") String name);
+
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/BomAccountLogRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/BomAccountLogRepository.java
new file mode 100644
index 0000000..ccc2c69
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/BomAccountLogRepository.java
@@ -0,0 +1,28 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.youchain.basicdata.repository;
+
+import com.youchain.basicdata.domain.BomAccountLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+/**
+* @website https://eladmin.vip
+* @author houjianlan
+* @date 2024-04-24
+**/
+public interface BomAccountLogRepository extends JpaRepository, JpaSpecificationExecutor {
+}
\ No newline at end of file
diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/BomAccountRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/BomAccountRepository.java
new file mode 100644
index 0000000..86bc6a6
--- /dev/null
+++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/BomAccountRepository.java
@@ -0,0 +1,72 @@
+/*
+* Copyright 2019-2020 Zheng Jie
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.youchain.basicdata.repository;
+
+import com.youchain.basicdata.domain.BigItem;
+import com.youchain.basicdata.domain.BomAccount;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+/**
+* @website https://eladmin.vip
+* @author baobinglin
+* @date 2024-01-02
+**/
+public interface BomAccountRepository extends JpaRepository, JpaSpecificationExecutor {
+ /**
+ * 唯一 查询
+ * @param big_item_id
+ * @param item_id
+ * @return
+ */
+ @Query(value = "SELECT * FROM base_bom_account ba WHERE ba.big_item_id=?1 and ba.item_id=?2 and ba.r_area_id=?3 and ba.z_point_id=?4", nativeQuery = true)
+ BomAccount findByOnly(Long big_item_id,Long item_id,Long r_area_id,Long z_point_id);
+
+ /**
+ * 查询说有的 接收仓库 为true的 bigitem
+ * @return
+ */
+ @Query(value = "SELECT * FROM `base_bom_account` b where b.r_area_id in (select a.id from base_area a where a.bexb=1) GROUP BY b.big_item_id", nativeQuery = true)
+ List queryBomAccountsBIidOne();
+
+ @Query(value = "select * from base_big_item where id in (SELECT DISTINCT b.big_item_id FROM `base_bom_account` b where b.r_area_id in (select a.id from base_area a where a.bexb=1) )", nativeQuery = true)
+ List queryBigItemALl();
+
+ @Query(value = "SELECT * FROM `base_bom_account` b where b.r_area_id=?1 and b.item_id=?2 and b.z_point_id=?3", nativeQuery = true)
+ List queryBomUnique(Long area_id, Long item_id, Long poin_id);
+ @Query(value = "SELECT IFNULL(sum(pc_qty),0) FROM `base_bom_account` b where b.r_area_id=?1 and b.item_id=?2 and b.z_point_id=?3", nativeQuery = true)
+ Double getPcQty(Long area_id, Long item_id, Long point_id);
+
+ @Query(value = "SELECT * FROM `base_bom_account` b where b.r_area_id=?1 and b.item_id=?2", nativeQuery = true)
+ List getBomList(Long area_id, Long item_id);
+
+ @Query(value = "SELECT * FROM `base_bom_account` b where b.item_id=?1", nativeQuery = true)
+ List getItemBomList( Long item_id);
+
+ @Query(value = "SELECT * FROM `base_bom_account` b where b.big_item_id=?1", nativeQuery = true)
+ List