初版提交

This commit is contained in:
凌尛 2026-06-15 13:48:57 +08:00
commit 35fa3721c5
1030 changed files with 114289 additions and 0 deletions

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
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:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) 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
(d) 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 [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

1
README.md Normal file
View File

@ -0,0 +1 @@
# erp

View File

@ -0,0 +1,351 @@
【2026-01-20 13:32:33】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-01-20 13:32:33】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2013484773489025025","taskType":"1","shopIds":"2006557053525397505","shopNames":"志诚纸品店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d301edd6-9de7-4b05-bf04-6cb671aa1b7c_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006557053525397505","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-01-20 13:39:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-01-20 13:39:40】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2013486565350219777","taskType":"1","shopIds":"2006557053525397505","shopNames":"志诚纸品店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/1fb39e22-29d5-49a3-9092-27234b2dc7e0_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006557053525397505","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"}
【2026-01-26 16:17:46】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-01-26 16:17:46】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2015700678402940929","taskType":"1","shopIds":"1995373681100910593","shopNames":"志诚图书店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":100,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":100,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/43d1e842-2645-4418-9af7-0a5239d3655a_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-01-26 16:17:57】【返回参数】null
【2026-01-26 16:17:57】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-01-26 16:52:35】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-01-26 16:52:35】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2015709440610181122","taskType":"1","shopIds":"1995373681100910593","shopNames":"志诚图书店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":100,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":100,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0ecc4aa4-3355-41db-8d9e-1b59b8532242_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"}
【2026-01-26 16:52:43】【返回参数】null
【2026-01-26 16:52:43】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-02-08 13:41:37】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-02-08 13:41:37】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2020372423449829378","taskType":"1","shopIds":"2006241414755627010","shopNames":"品博","fileName":"excel表格更新:task_template_1770529245267.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":5,"fileName":"task_template_1770529245267.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f16eb452-b33d-494f-9849-51f503d9d2bd_task_template_1770529245267.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006241414755627010","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-02-08 13:41:37】【返回参数】null
【2026-02-08 13:41:37】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-02-08 13:47:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-02-08 13:47:40】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2020373948133859330","taskType":"1","shopIds":"2006241414755627010","shopNames":"品博","fileName":"excel表格更新:task_template_1770529245267.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":5,"fileName":"task_template_1770529245267.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/24a7401d-b340-41f0-981a-03c522b2a77e_task_template_1770529245267.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006241414755627010","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-02-08 13:47:41】【返回参数】null
【2026-02-08 13:47:41】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-02-08 13:54:02】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-02-08 13:54:02】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2020375549208748033","taskType":"1","shopIds":"2006241414755627010","shopNames":"品博","fileName":"excel表格更新:task_template_1770529245267.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":5,"fileName":"task_template_1770529245267.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d0a34799-1aeb-4e1e-b031-39a1c2849adc_task_template_1770529245267.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006241414755627010","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-02-08 13:54:03】【返回参数】null
【2026-02-08 13:54:03】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:10:17】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:10:17】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/2f011223-3ab4-460e-97b5-41d55700e34c_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-04 17:10:32】【系统异常】【异常方法】addGoods
【2026-03-04 17:10:32】【系统异常】【异常内容】java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
at java.base/java.util.HashMap.forEach(HashMap.java:1421)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:248)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2026-03-04 17:10:32】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:11:17】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:11:17】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4af5b618-5d3f-456c-a9c1-ad4e957639ff_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-04 17:11:48】【系统异常】【异常方法】addGoods
【2026-03-04 17:11:48】【系统异常】【异常内容】java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
at java.base/java.util.HashMap.forEach(HashMap.java:1421)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:248)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2026-03-04 17:11:48】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:13:11】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:13:11】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b97adc6a-5512-442f-8a96-52183021e6eb_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-04 17:13:40】【系统异常】【异常方法】addGoods
【2026-03-04 17:13:40】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:250)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2026-03-04 17:13:40】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:13:56】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:13:56】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/8eb77905-7c95-40a6-a8c0-acc547dc2512_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-04 17:14:12】【系统异常】【异常方法】addGoods
【2026-03-04 17:14:12】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:250)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2026-03-04 17:14:12】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:15:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:15:27】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7b761a18-ad42-4cc1-95ee-83160446a2d3_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-04 17:16:01】【系统异常】【异常方法】addGoods
【2026-03-04 17:16:01】【系统异常】【异常内容】java.lang.ClassCastException: class java.util.HashMap cannot be cast to class java.lang.String (java.util.HashMap and java.lang.String are in module java.base of loader 'bootstrap')
at java.base/java.util.HashMap.forEach(HashMap.java:1421)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:264)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2026-03-04 17:16:01】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:17:25】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:17:25】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/dd92d5b1-677e-4ce6-ae96-92d2004c88c9_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-04 17:18:06】【系统异常】【异常方法】addGoods
【2026-03-04 17:18:07】【系统异常】【异常内容】java.lang.ClassCastException: class java.util.HashMap cannot be cast to class java.lang.String (java.util.HashMap and java.lang.String are in module java.base of loader 'bootstrap')
at java.base/java.util.HashMap.forEach(HashMap.java:1421)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:264)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2026-03-04 17:18:14】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:21:48】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-04 17:21:48】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/896274d9-d773-4a22-bc5a-3852cc794b43_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-04 17:25:35】【系统异常】【异常方法】addGoods
【2026-03-04 17:25:35】【系统异常】【异常内容】java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.lang.String (java.util.ArrayList and java.lang.String are in module java.base of loader 'bootstrap')
at java.base/java.util.HashMap.forEach(HashMap.java:1421)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:266)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2026-03-04 17:25:35】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:10:01】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:10:01】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0e1fb1d8-29af-49d4-9a1d-0a36f5533c81_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:10:29】【返回参数】null
【2026-03-05 13:10:29】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:12:09】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:12:09】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a892e033-5c93-4b48-b70a-adc5acf751db_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:12:10】【返回参数】null
【2026-03-05 13:12:10】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:13:16】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:13:16】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ac313af0-7711-4bf1-af46-472f1552bfba_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:23:57】【返回参数】null
【2026-03-05 13:23:57】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:25:18】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:25:18】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/64ac0c9d-cac4-4624-95be-479818295e2e_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:33:26】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:33:26】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/735f415f-0458-432f-a58d-7e49751c9f4d_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:37:45】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:37:45】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/86a57566-0fa0-4c36-98a9-8fbdd1e5a778_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:40:23】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:40:23】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/09f17fa6-36a0-4e56-b51c-30854417d708_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:40:29】【系统异常】【异常方法】addGoods
【2026-03-05 13:40:29】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://103.236.74.207:8283/task/create": Connect timed out
at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:926)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:906)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:248)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: java.net.SocketTimeoutException: Connect timed out
at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:551)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602)
at java.base/java.net.Socket.connect(Socket.java:633)
at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:534)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:639)
at java.base/sun.net.www.http.HttpClient.<init>(HttpClient.java:282)
at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:387)
at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:409)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1308)
at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1241)
at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1127)
at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1056)
at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79)
at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:71)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900)
... 28 more
【2026-03-05 13:40:29】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:40:57】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:40:57】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/83b138df-c60b-4288-8ff3-e79b756c7386_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:41:59】【返回参数】null
【2026-03-05 13:41:59】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:45:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 13:45:15】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0f6883b3-6038-4d34-9b1b-9a4e5db7fb1f_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 13:45:17】【返回参数】null
【2026-03-05 13:45:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 15:01:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 15:01:39】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b64ceafc-e75c-4725-a987-421f345226d5_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"}
【2026-03-05 15:01:40】【返回参数】null
【2026-03-05 15:01:40】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 17:28:29】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 17:28:29】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/104f3c70-22ef-4598-838d-8946b7866561_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2029489046873382913\",\"msg\":\"成功\"}\n"},"userId":"1916358871501082626"}
【2026-03-05 17:28:35】【返回参数】null
【2026-03-05 17:28:35】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 17:35:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-05 17:35:19】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ae73d8c0-d17f-422b-b3ea-2790f48e2001_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2029490760825380865\",\"msg\":\"成功\"}\n"},"userId":"1916358871501082626"}
【2026-03-10 09:57:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-10 09:57:39】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0f16470e-d7d2-4a74-95ca-527b6b6926be_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"}
【2026-03-10 10:00:10】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-10 10:00:10】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/71b08c28-455f-4ca1-bf28-4cfe8d21716a_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"}
【2026-03-10 10:03:52】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-03-10 10:03:52】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/e276e4e4-b52f-4074-9d44-0a4ed8ac153b_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"}
【2026-03-10 10:04:09】【返回参数】null
【2026-03-10 10:04:09】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods

View File

@ -0,0 +1,336 @@
【2025-11-08 08:43:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-11-08 08:43:34】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1986957732971384833","taskType":"EDIT_STOCK_GOODS","shopIds":"1940355994419642369","shopNames":"古威文具礼品专营店","fileName":"excel表格上传:更新库存.xlsx","dataNum":3,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"EDIT_STOCK_GOODS","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1940355994419642369","data":{"total":3,"fileName":"更新库存.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/50894f85-9a07-4527-b117-b4c1b05dde6f_更新库存.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1965254774327533570"}
【2025-11-08 08:43:34】【系统异常】【异常方法】addGoods
【2025-11-08 08:43:34】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "String.toCharArray()" because "val" is null
at java.base/java.math.BigDecimal.<init>(BigDecimal.java:900)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:244)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2025-11-08 08:43:34】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-11-08 08:44:48】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-11-08 08:44:48】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1986958045090516994","taskType":"EDIT_STOCK_GOODS","shopIds":"1940355994419642369","shopNames":"古威文具礼品专营店","fileName":"excel表格上传:更新库存.xlsx","dataNum":3,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"EDIT_STOCK_GOODS","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1940355994419642369","data":{"total":3,"fileName":"更新库存.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/91c2c5eb-9a9c-44e9-b4bb-4ac784133f20_更新库存.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1965254774327533570"}
【2025-11-08 08:44:48】【系统异常】【异常方法】addGoods
【2025-11-08 08:44:48】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "String.toCharArray()" because "val" is null
at java.base/java.math.BigDecimal.<init>(BigDecimal.java:900)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:244)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
【2025-11-08 08:44:48】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-13 09:20:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-13 09:20:51】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2043499624554655746","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:新发布商品模板.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f91c2096-854d-4a73-8fa0-40a8075fff50_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1965254774327533570"}
【2026-04-13 09:20:53】【返回参数】null
【2026-04-13 09:20:53】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 10:26:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 10:26:05】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/9d359ccb-32ea-4b5f-a19c-07ad5d299636_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2044603196746182658\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 10:26:06】【返回参数】null
【2026-04-16 10:26:06】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:06:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:06:15】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ce467766-d204-4a7b-bac4-dc5a9b506163_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044673709124284417\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:06:15】【返回参数】null
【2026-04-16 15:06:15】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:07:10】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:07:10】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f5639497-2949-4a0a-8c9e-1970bdbaca49_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044673940914106369\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:07:36】【返回参数】null
【2026-04-16 15:07:36】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:09:35】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:09:35】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a2f18b45-dc29-4a91-9af3-f74e0cb2287b_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044674547817312258\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:09:55】【返回参数】null
【2026-04-16 15:09:55】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:11:32】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:11:32】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7803a21e-3f1a-4ed9-949a-01cdd51667c5_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044675039247134722\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:11:35】【返回参数】null
【2026-04-16 15:11:35】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:14:37】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:14:37】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/08e13481-da0d-4443-95b1-99031ad198b7_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044675816292282369\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:14:38】【返回参数】null
【2026-04-16 15:14:38】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:15:50】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:15:50】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/6721fcbf-e7bb-42c5-b86b-0eb9ba68d9a8_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2044676123617325058\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:15:51】【返回参数】null
【2026-04-16 15:15:51】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:16:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:16:39】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a3271d95-2ced-453c-9c59-8843c87d1efb_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044676325912801282\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:18:36】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:18:36】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0d8e7f18-ced5-4e95-b79d-1a9c5b3a1994_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044676819477524482\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:18:59】【返回参数】null
【2026-04-16 15:18:59】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:22:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:22:05】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/76c9e511-af83-4188-9ec9-339544ba89ae_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044677694208012290\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-16 15:22:05】【返回参数】null
【2026-04-16 15:22:05】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:24:23】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:24:23】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044678275270795266","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4a997bb6-a82e-46f0-8854-605b77f5f59f_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-04-16 15:24:24】【返回参数】null
【2026-04-16 15:24:24】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:26:16】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:26:16】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044678748044337154","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/59abecc2-6509-45be-a2e5-b62dd11bb72c_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-04-16 15:26:17】【返回参数】null
【2026-04-16 15:26:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:27:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:27:19】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044679013053046786","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/fb88b057-1f65-4be3-a08a-4b3a4e5ed085_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-04-16 15:27:20】【返回参数】null
【2026-04-16 15:27:20】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:30:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:30:05】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044679707529060354","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c2fd224d-93e7-4e25-8906-ce34e3867184_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-04-16 15:30:16】【返回参数】null
【2026-04-16 15:30:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:31:13】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:31:13】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044679992125169665","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4817c483-0313-4732-a3d5-a2c85f52672a_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-04-16 15:31:16】【返回参数】null
【2026-04-16 15:31:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:33:36】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-16 15:33:36】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044680595056369665","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/2376be6d-86ab-4b37-aa38-99c9ea38cccf_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-04-16 15:33:37】【返回参数】null
【2026-04-16 15:33:37】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-17 15:22:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-17 15:22:27】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":133535,"fileName":"task_template_1776408308595.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/dccd453a-bce1-4eea-8be5-8b14398b9091_task_template_1776408308595.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2045040173987557377\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-17 15:31:08】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-17 15:31:08】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":133535,"fileName":"task_template_1776408308595.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7b0cedd6-5139-42a3-8e4d-708826773270_task_template_1776408308595.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2045042358829871105\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 14:51:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 14:51:27】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7b1ea6a0-f39d-4dc4-9efb-e59799d33a11_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2046119528465633281\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 14:52:00】【返回参数】null
【2026-04-20 14:52:00】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 14:54:02】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 14:54:02】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7bd22644-6316-444c-b4f8-d0f4690f25d9_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046120179140595714\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 14:56:52】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 14:56:52】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4dfde870-33c7-4cc4-834a-e53c74b4cae4_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046120893040496641\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 14:57:36】【返回参数】null
【2026-04-20 14:57:36】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:05:50】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:05:50】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ec66bb8b-69dc-412d-8494-a7bba8b48316_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046123147927687170\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:06:20】【返回参数】null
【2026-04-20 15:06:20】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:10:06】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:10:06】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ec66bb8b-69dc-412d-8494-a7bba8b48316_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046124222147661825\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:10:17】【返回参数】null
【2026-04-20 15:10:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:29:41】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:29:41】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c29629cc-0ce2-4651-9a71-826a85c3d4ea_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046129148831666177\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:29:46】【返回参数】null
【2026-04-20 15:29:46】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:31:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:31:34】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/9173f024-bf8d-452a-af10-8941f70e5b95_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046129621793968129\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:31:39】【返回参数】null
【2026-04-20 15:31:39】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:32:43】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:32:43】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d04844b3-493e-4a8f-b252-294adf31632d_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046129914136956930\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:32:49】【返回参数】null
【2026-04-20 15:32:49】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:34:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:34:40】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/8cebea0b-408b-40a4-bae8-7745fcf99a67_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046130402291027969\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:34:45】【返回参数】null
【2026-04-20 15:34:45】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:36:09】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:36:09】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7fb41e5e-88c3-4aab-80c2-f7f34acf2c89_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046130778071306242\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:36:15】【返回参数】null
【2026-04-20 15:36:15】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:42:12】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:42:12】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/e51e95d1-e75e-4fca-91ea-ad14495aeef8_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046132298221293570\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:42:17】【返回参数】null
【2026-04-20 15:42:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:43:06】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:43:06】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/5cfe33c4-d678-4dda-b692-2484f733cbaa_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046132525678399490\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:43:11】【返回参数】null
【2026-04-20 15:43:11】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:46:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:46:30】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7f56b37d-dc50-4b1b-afad-1f0b94476ce7_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046133383535202305\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:46:36】【返回参数】null
【2026-04-20 15:46:36】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:48:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-20 15:48:51】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/91894544-f7b2-4977-9b60-c6717e4c204f_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046133972956549122\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-20 15:48:56】【返回参数】null
【2026-04-20 15:48:56】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-21 15:34:03】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-21 15:34:03】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7d606bd4-718d-4632-a862-0bc6423aba1a_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046492643871916034\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-21 15:35:18】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-21 15:35:18】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/6c44f2e6-77bf-4546-8328-3767483b134a_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2046492961305231362\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-21 16:55:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-21 16:55:34】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/93de46fe-f77d-4b90-bf10-65044b53fcdb_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046513159244570626\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-21 16:55:57】【返回参数】null
【2026-04-21 16:55:57】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-21 16:56:26】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-21 16:56:26】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0c409529-4a38-4adf-b34b-5ae86caf2eba_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046513379311312897\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-04-21 16:56:48】【返回参数】null
【2026-04-21 16:56:48】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-09 11:45:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-09 11:45:15】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":6,"fileName":"志诚.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/43e733bd-b6d9-4b01-b644-fd67c501e6bf_志诚.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2052958038187192321\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-09 11:45:16】【返回参数】null
【2026-05-09 11:45:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-09 11:48:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-09 11:48:30】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":4,"fileName":"闲鱼商品.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b395071d-127a-48f5-a9da-e7047e9b072c_闲鱼商品.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2052958856936304642\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-09 11:48:30】【返回参数】null
【2026-05-09 11:48:30】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-09 13:20:01】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-09 13:20:01】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":4,"fileName":"闲鱼商品.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/51291a87-9af4-4cb6-9f54-94794db7f69c_闲鱼商品.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2052981886706135042\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-09 13:20:01】【返回参数】null
【2026-05-09 13:20:01】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-16 13:20:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-16 13:20:34】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":7,"fileName":"加密表格.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/be61ca59-b074-4f5e-a649-0e68a7eed3fb_加密表格.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2054805126617468929","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055518748859691009\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"}
【2026-05-16 13:25:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-16 13:25:19】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":7,"fileName":"加密表格.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/66b41482-acc1-4a6e-a856-9d29047cd28d_加密表格.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055519946794856450\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2054805126617468929","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-16 13:26:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-16 13:26:39】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":7,"fileName":"加密表格.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/2f217c7a-45c1-4903-8ac8-d94d3c3b4f85_加密表格.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055520280783089666\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2054805126617468929","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-16 13:28:54】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-16 13:28:54】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":6,"fileName":"志诚.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/87379338-3fa3-4557-ac15-956e9738b6dd_志诚.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055520846435315713\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2054805126617468929","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-18 11:52:25】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 11:52:25】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2056221341643239426","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:简创甄选书籍-测试数据.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c08b3732-7557-4892-834c-ea37aa3d035b_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-05-18 11:52:25】【系统异常】【异常方法】addGoods
【2026-05-18 11:52:25】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:840)
【2026-05-18 11:52:25】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 11:53:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 11:53:05】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2056221510325563394","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:简创甄选书籍-测试数据.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/77d39ea1-9c47-495c-9273-04e430e09e5f_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-05-18 11:53:12】【系统异常】【异常方法】addGoods
【2026-05-18 11:53:12】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:840)
【2026-05-18 11:53:12】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 11:53:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 11:53:30】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2056221614864396289","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:简创甄选书籍-测试数据.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/302ca3a5-5629-48d2-8b37-2ea0036c8b25_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"}
【2026-05-18 11:55:22】【系统异常】【异常方法】addGoods
【2026-05-18 11:55:22】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:840)
【2026-05-18 11:55:22】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 11:57:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 11:57:34】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/385afd29-24b2-4c80-a239-d09c71b9de46_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056222637107929089\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2031685168119377922","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-18 11:57:43】【返回参数】null
【2026-05-18 11:57:43】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 13:03:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 13:03:51】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/54dd6d25-c4f0-4501-9b66-aae1be13c16c_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056239317095768065\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2031685168119377922","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-18 13:03:54】【返回参数】null
【2026-05-18 13:03:54】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 14:33:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 14:33:27】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/6a6f3bbc-a367-479f-9a55-db129cbedaef_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2056261865716015106\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-18 14:37:29】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 14:37:29】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f1be0ec8-f095-4dc9-94d5-fde7e5404101_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056262883182862338\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2031685168119377922","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-18 14:37:30】【返回参数】null
【2026-05-18 14:37:30】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 14:39:07】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-18 14:39:07】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d1063931-7a40-4595-8e7f-d240f76e48f3_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056263292014256130\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828096496140289","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-05-18 14:39:07】【返回参数】null
【2026-05-18 14:39:07】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-06-03 15:09:49】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-06-03 15:09:49】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":198,"fileName":"闲鱼.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a36296b5-3c88-41e1-bf2c-1ef8d13f6080_闲鱼.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2062069223054589954\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}
【2026-06-03 15:14:21】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-06-03 15:14:21】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":198,"fileName":"闲鱼.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d4e36220-61f5-4bb9-9167-53870cafbe45_闲鱼.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2062070365880795138\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
【2026-05-28 15:01:10】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-05-28 15:01:10】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":293,"fileName":"task_template_1779944336050.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4bc95289-eeb0-4722-8531-3deee41a9729_task_template_1779944336050.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2059892720069992449\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1983373997176135681","proportion":100,"addNum":0}],"shopIds":"2059539257909739521","synchronizationType":"1","bookCategory":"0"},"userId":"1983373997176135681"}
【2026-05-28 15:02:23】【返回参数】null
【2026-05-28 15:02:23】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods

View File

@ -0,0 +1,203 @@
【2025-09-18 18:03:25】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-09-18 18:03:26】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1968616845749116930","taskType":"1","shopIds":"1968345938572304386","shopNames":"棵韵KEOYURNE图书旗舰店","fileName":"excel表格上传:知书上货模版 - 副本.xlsx","dataNum":33,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1968345938572304386","data":{"total":33,"fileName":"知书上货模版 - 副本.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1}
【2025-09-18 18:04:13】【系统异常】【异常方法】addGoods
【2025-09-18 18:04:13】【系统异常】【异常内容】java.lang.RuntimeException: java.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:233)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: java.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx
at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:309)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:231)
... 24 more
Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:2018)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1610)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224)
at java.base/java.net.URL.openStream(URL.java:1161)
at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:303)
... 25 more
【2025-09-18 18:04:13】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-09-18 18:05:47】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-09-18 18:05:47】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1968617440169996290","taskType":"1","shopIds":"1968345938572304386","shopNames":"棵韵KEOYURNE图书旗舰店","fileName":"excel表格上传:知书上货模版.xlsx","dataNum":33,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"1","bookCategory":"0","shopIds":"1968345938572304386","data":{"total":33,"fileName":"知书上货模版.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/570eb2d9-9ec7-48d9-a4b0-eb7f5788c925_知书上货模版.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1}
【2025-09-18 18:08:07】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-09-18 18:08:07】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1968618027657789441","taskType":"1","shopIds":"1968345938572304386","shopNames":"棵韵KEOYURNE图书旗舰店","fileName":"excel表格上传:知书上货模版.xlsx","dataNum":33,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"1","bookCategory":"0","shopIds":"1968345938572304386","data":{"total":33,"fileName":"知书上货模版.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/aa38cb76-3464-4b93-8ffa-c378b025981e_知书上货模版.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1}
【2025-09-18 18:09:47】【返回参数】null
【2025-09-18 18:09:47】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-10-09 20:36:50】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-10-09 20:36:50】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1976265599406866434","taskType":"1","shopIds":"1976212171971805186","shopNames":"欲泽居家拖鞋专营店","fileName":"excel表格上传:1 (2).xlsx","dataNum":115788,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1976212171971805186","data":{"total":115788,"fileName":"1 (2).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx"},"imageSelect":"1","deleteNum":0},"userId":1}
【2025-10-09 20:37:27】【系统异常】【异常方法】addGoods
【2025-10-09 20:37:27】【系统异常】【异常内容】java.lang.RuntimeException: java.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:234)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:842)
Caused by: java.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx
at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:309)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:232)
... 24 more
Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:2018)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1610)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224)
at java.base/java.net.URL.openStream(URL.java:1161)
at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:303)
... 25 more
【2025-10-09 20:37:27】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-10-14 14:16:18】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2025-10-14 14:16:18】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1977981773408706561","taskType":"1","shopIds":"1977668615057432578","shopNames":"云眠书籍专营店","fileName":"excel表格上传:1.xlsx","dataNum":58628,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1977668615057432578","data":{"total":58628,"fileName":"1.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f7d49467-3805-4f0f-b8b2-a30490b5fc87_1.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1}
【2026-04-03 14:12:12】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:12:12】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c54e1f5d-4a0d-46a7-9ca5-2333e9bba455_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039949064445775874\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 14:12:14】【返回参数】null
【2026-04-03 14:12:14】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:31:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:31:05】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ddb09ef2-3402-4a3a-84f7-5a498e09556e_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039953815631712258\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 14:31:08】【返回参数】null
【2026-04-03 14:31:08】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:37:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:37:40】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ef416bf3-0f56-4adc-b950-be4c6343141d_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039955473279373313\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 14:37:43】【返回参数】null
【2026-04-03 14:37:43】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:42:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:42:30】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/96f302c4-ec51-4144-97af-875389c2a769_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039956688440545282\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 14:42:33】【返回参数】null
【2026-04-03 14:42:33】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:50:33】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 14:50:33】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/276af74c-8e55-41e5-9e62-5faee13ff42e_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039958713328881665\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 14:51:52】【返回参数】null
【2026-04-03 14:51:52】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:01:56】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:01:56】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0a4466b1-28de-42fb-a926-4cc221a9016e_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039961581154881538\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 15:31:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:31:30】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/64be1f86-09df-41e0-a87a-c116eb2d838d_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039969020432515073\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 15:32:55】【返回参数】null
【2026-04-03 15:32:55】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:37:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:37:19】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"proportion":100,"addNum":0}],"data":{"total":51,"fileName":"4.3上传发布.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7144a800-d9d3-4bb4-b385-75494669d824_4.3上传发布.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039970485242855425\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 15:38:14】【返回参数】null
【2026-04-03 15:38:14】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:42:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:42:15】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":51,"fileName":"4.3上传发布.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/228912ff-8e20-4881-8e3f-8db839b520da_4.3上传发布.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039971725540491265\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 15:42:16】【系统异常】【异常方法】addGoods
【2026-04-03 15:42:16】【系统异常】【异常内容】org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error on POST request for "http://36.212.20.113:8182/api/goods/simple": "{"code":500,"message":"系统内部错误","success":false}"
at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:102)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:189)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:147)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:953)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:902)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:264)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:840)
【2026-04-03 15:42:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:45:04】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-04-03 15:45:04】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"data":{"total":51,"fileName":"4.3上传发布.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/5d89e6b8-7fb4-4840-8817-beeaf1e19951_4.3上传发布.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039972434512084994\",\"msg\":\"成功\"}\n"},"userId":1}
【2026-04-03 15:45:10】【系统异常】【异常方法】addGoods
【2026-04-03 15:45:10】【系统异常】【异常内容】org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error on POST request for "http://36.212.20.113:8182/api/goods/simple": "{"code":500,"message":"系统内部错误","success":false}"
at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:102)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:189)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:147)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:953)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:902)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549)
at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:264)
at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42)
at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods(<generated>)
at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39)
at java.base/java.lang.Thread.run(Thread.java:840)
【2026-04-03 15:45:10】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-06-04 17:34:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods
【2026-06-04 17:34:51】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":34237,"fileName":"漫游鲸童书奥莱店(更新价格库存).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/433e6243-db36-4fb3-9bf9-bea1242c9f48_漫游鲸童书奥莱店更新价格库存.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2062468107744514049\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"shopIds":"2062044901082611714","synchronizationType":"1","bookCategory":"0"},"userId":1}

520
pom.xml Normal file
View File

@ -0,0 +1,520 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>${revision}</version>
<name>ZhiShu</name>
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
<description>Dromara RuoYi-Vue-Plus多租户管理系统</description>
<properties>
<revision>5.3.0</revision>
<spring-boot.version>3.4.2</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
<mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.8.4</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<easyexcel.version>4.0.3</easyexcel.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.40.0</satoken.version>
<mybatis-plus.version>3.5.10</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.35</hutool.version>
<spring-boot-admin.version>3.4.1</spring-boot-admin.version>
<redisson.version>3.44.0</redisson.version>
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<snailjob.version>1.3.0</snailjob.version>
<mapstruct-plus.version>1.4.6</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.36</lombok.version>
<bouncycastle.version>1.76</bouncycastle.version>
<justauth.version>1.16.7</justauth.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<!-- OSS 配置 -->
<aws.sdk.version>2.28.22</aws.sdk.version>
<aws.crt.version>0.31.3</aws.crt.version>
<!-- SMS 配置 -->
<sms4j.version>3.3.3</sms4j.version>
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20250101</anyline.version>
<!--工作流配置-->
<warm-flow.version>1.6.6</warm-flow.version>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
</properties>
<profiles>
<profile>
<id>local</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active>
<logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active>
<logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
<activation>
<!-- 默认环境 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
<logging.level>warn</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties>
</profile>
</profiles>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- SpringBoot的依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Warm-Flow国产工作流引擎, 在线文档http://warm-flow.cn/ -->
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-mybatis-plus-sb3-starter</artifactId>
<version>${warm-flow.version}</version>
</dependency>
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-plugin-ui-sb-web</artifactId>
<version>${warm-flow.version}</version>
</dependency>
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
<!-- common 的依赖配置-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-bom</artifactId>
<version>${revision}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc</artifactId>
<version>${therapi-javadoc.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${satoken.version}</version>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- sql性能分析插件 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<!-- AWS SDK for Java 2.x -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!-- 使用AWS基于 CRT 的 S3 客户端 -->
<dependency>
<groupId>software.amazon.awssdk.crt</groupId>
<artifactId>aws-crt</artifactId>
<version>${aws.crt.version}</version>
</dependency>
<!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!--短信sms4j-->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>${sms4j.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
<version>${lock4j.version}</version>
</dependency>
<!-- SnailJob Client -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-starter</artifactId>
<version>${snailjob.version}</version>
</dependency>
<!-- snail-job 客户端核心依赖 -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-job-core</artifactId>
<version>${snailjob.version}</version>
</dependency>
<!-- snail-job 重试相关依赖 -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-retry-core</artifactId>
<version>${snail-job.version}</version>
</dependency>
<!-- 加密包引入 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>
<!-- 离线IP地址定位库 ip2region -->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-zhishu</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-demo</artifactId>
<version>${revision}</version>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-workflow</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>ruoyi-admin</module>
<module>ruoyi-common</module>
<module>ruoyi-extend</module>
<module>ruoyi-modules</module>
</modules>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc-scribe</artifactId>
<version>${therapi-javadoc.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${mapstruct-plus.lombok.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 单元测试使用 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
<!-- 根据打包环境执行对应的@Tag测试方法 -->
<groups>${profiles.active}</groups>
<!-- 排除标签 -->
<excludedGroups>exclude</excludedGroups>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<!-- 统一版本号管理 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<!-- 关闭过滤 -->
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<!-- 引入所有 匹配文件进行过滤 -->
<includes>
<include>application*</include>
<include>bootstrap*</include>
<include>banner*</include>
</includes>
<!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

30
ruoyi-admin/Dockerfile Normal file
View File

@ -0,0 +1,30 @@
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
#FROM findepi/graalvm:java17-native
LABEL maintainer="Lion Li"
RUN mkdir -p /ruoyi/server/logs \
/ruoyi/server/temp \
/ruoyi/skywalking/agent
WORKDIR /ruoyi/server
ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
EXPOSE ${SERVER_PORT}
ADD ./target/ruoyi-admin.jar ./app.jar
# 工作流字体文件
ADD ./zhFonts/ /usr/share/fonts/zhFonts/
SHELL ["/bin/bash", "-c"]
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
#-Dskywalking.agent.service_name=ruoyi-server \
#-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
-jar app.jar

181
ruoyi-admin/pom.xml Normal file
View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ruoyi-admin</artifactId>
<description>
web服务入口
</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;-->
<!-- &lt;!&ndash; Oracle &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.jdbc</groupId>-->
<!-- <artifactId>ojdbc8</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.nls</groupId>-->
<!-- <artifactId>orai18n</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; PostgreSql &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; SqlServer &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.microsoft.sqlserver</groupId>-->
<!-- <artifactId>mssql-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-zhishu</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-workflow</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- skywalking 整合 logback -->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-trace</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<!-- <dependency>-->
<!-- <groupId>com.google.zxing</groupId>-->
<!-- <artifactId>core</artifactId>-->
<!-- <version>3.3.0</version>-->
<!-- </dependency>-->
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,18 @@
package org.dromara;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* web容器中进行部署
*
* @author Lion Li
*/
public class DromaraServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(DromaraApplication.class);
}
}

View File

@ -0,0 +1,507 @@
package org.dromara.web.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.*;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.*;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.*;
import org.dromara.web.domain.vo.LoginTenantVo;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.domain.vo.TenantListVo;
import org.dromara.web.domain.vo.WxLoginVo;
import org.dromara.web.domain.vo.dto.UserLoginDTO;
import org.dromara.web.domain.vo.dto.WxRegisterDTO;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService;
import org.dromara.zhishu.service.SignGeneratorService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 认证
*
* @author Lion Li
*/
@Slf4j
@SaIgnore
@RequiredArgsConstructor
@RestController
@RequestMapping("/auth")
@CrossOrigin(origins = "https://erp.newadmin.buzhiyushu.cn",maxAge = 3600)
public class AuthController {
private final SocialProperties socialProperties;
private final SysLoginService loginService;
private final SysRegisterService registerService;
private final ISysConfigService configService;
private final ISysTenantService tenantService;
private final ISysSocialService socialUserService;
private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService;
private final ISysUserService userService;
private final SignGeneratorService signGeneratorService;
@Value("${wechat.appid}")
private String appid;
@Value("${wechat.secret}")
private String secret;
@Value("${wechat.jscode2session-url}")
private String loginUrl;
/**
* 登录方法
*
* @param body 登录信息
* @return 结果
*/
//@ApiEncrypt
@PostMapping("/login")
public R<LoginVo> login(@RequestBody String body) {
// System.out.println("body:" + body);
LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class);
long timestamp1 = System.currentTimeMillis() / 1000;
String sign = null;
if (loginBody != null) {
sign = signGeneratorService.generateCallbackSign(loginBody.getLogin_code(), timestamp1, "erp_callback_sk_7f8a9b2c4d5e6f1a3b7c9d2e4f5a6b8c");
}
ValidatorUtils.validate(loginBody);
// 授权类型和客户端id
String clientId = loginBody.getClientId();
String grantType = loginBody.getGrantType();
// System.out.println("===============" + grantType);
SysClientVo client = clientService.queryByClientId(clientId);
// System.out.println(client);
// 查询不到 client client 内不包含 grantType
if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType);
return R.fail(MessageUtils.message("auth.grant.type.error"));
} else if (SystemConstants.NORMAL.equals(client.getStatus())) {
return R.fail(MessageUtils.message("auth.grant.type.blocked"));
}
// 校验租户
loginService.checkTenant(loginBody.getTenantId());
// 登录
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
if (!StringUtils.isEmpty(loginBody.getLogin_code())){
// 调用 ERP 回调 API
try {
//入口层
String callbackUrl = "https://wallet.api.buzhiyushu.cn/api/oauth/erp/callback";
URL url = new URL(callbackUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
// URL编码所有参数值
StringBuilder postData = new StringBuilder();
postData.append("login_code=").append(URLEncoder.encode(
String.valueOf(loginBody.getLogin_code()), "UTF-8"));
postData.append("&erp_user_id=").append(URLEncoder.encode(
String.valueOf(LoginHelper.getUserId()), "UTF-8"));
postData.append("&erp_token=").append(URLEncoder.encode(
String.valueOf(loginVo.getAccessToken()), "UTF-8"));
postData.append("&erp_username=").append(URLEncoder.encode(
String.valueOf(userService.selectUserById(LoginHelper.getUserId()).getUserName()), "UTF-8"));
postData.append("&timestamp=").append(URLEncoder.encode(
String.valueOf(timestamp1), "UTF-8"));
postData.append("&sign=").append(URLEncoder.encode(
String.valueOf(sign), "UTF-8"));
// 打印请求信息用于调试
log.info("发送请求到: {}, 参数: {}", callbackUrl, postData.toString());
byte[] postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8);
connection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
try (OutputStream os = connection.getOutputStream()) {
os.write(postDataBytes);
os.flush();
}
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
log.error("ERP 回调 API 调用失败,状态码: {}", responseCode);
// 读取错误信息
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
log.error("错误响应: {}", response.toString());
}
} else {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
log.info("ERP 回调 API 调用成功,响应: {}", response.toString());
}
}
connection.disconnect();
} catch (Exception e) {
log.error("调用 ERP 回调 API 时发生异常", e);
}
}
Long userId = LoginHelper.getUserId();
scheduledExecutorService.schedule(() -> {
SseMessageDto dto = new SseMessageDto();
dto.setMessage("欢迎登录知书图书助理后台管理系统");
dto.setUserIds(List.of(userId));
SseMessageUtils.publishMessage(dto);
}, 5, TimeUnit.SECONDS);
// System.out.println("000000000000" + loginVo);
return R.ok(loginVo);
}
@PostMapping("/interFaceLogin")
public R<LoginVo> interFaceLogin(InterfaceLoginBody loginBody){
// System.out.println("body:" + loginBody);
String clientId = loginBody.getClientId();
SysClientVo client = clientService.queryByClientId(clientId);
String phoneNumber = loginBody.getPhoneNumber();
String password = loginBody.getPassword();
SysUserVo userVo = userService.selectUserByPhonenumber(phoneNumber);
if (userVo == null) {
log.error("用户手机号 {} 未找到对应的用户记录", phoneNumber);
throw new ServiceException("用户未找到对应的用户记录");
}
// 验证密码是否正确
if (!BCrypt.checkpw(password, userVo.getPassword())) {
log.error("用户密码不正确");
throw new ServiceException("用户密码不正确");
}
LoginUser loginUser = loginService.buildLoginUser(userVo);
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token
LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
loginVo.setPhoneNumber(phoneNumber);
loginVo.setNickName(loginUser.getNickname());
loginVo.setUserId(userVo.getUserId());
return R.ok(loginVo);
}
/**
* 获取跳转URL
*
* @param source 登录来源
* @return 结果
*/
@GetMapping("/binding/{source}")
public R<String> authBinding(@PathVariable("source") String source,
@RequestParam String tenantId, @RequestParam String domain) {
SocialLoginConfigProperties obj = socialProperties.getType().get(source);
if (ObjectUtil.isNull(obj)) {
return R.fail(source + "平台账号暂不支持");
}
AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties);
Map<String, String> map = new HashMap<>();
map.put("tenantId", tenantId);
map.put("domain", domain);
map.put("state", AuthStateUtils.createState());
String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8));
return R.ok("操作成功", authorizeUrl);
}
/**
* 前端回调绑定授权(需要token)
*
* @param loginBody 请求体
* @return 结果
*/
@PostMapping("/social/callback")
public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
// 校验token
StpUtil.checkLogin();
// 获取第三方登录信息
AuthResponse<AuthUser> response = SocialUtils.loginAuth(
loginBody.getSource(), loginBody.getSocialCode(),
loginBody.getSocialState(), socialProperties);
AuthUser authUserData = response.getData();
// 判断授权响应是否成功
if (!response.ok()) {
return R.fail(response.getMsg());
}
loginService.socialRegister(authUserData);
return R.ok();
}
/**
* 取消授权(需要token)
*
* @param socialId socialId
*/
@DeleteMapping(value = "/unlock/{socialId}")
public R<Void> unlockSocial(@PathVariable Long socialId) {
// 校验token
StpUtil.checkLogin();
Boolean rows = socialUserService.deleteWithValidById(socialId);
return rows ? R.ok() : R.fail("取消授权失败");
}
/**
* 退出登录
*/
@PostMapping("/logout")
public R<Void> logout() {
loginService.logout();
return R.ok("退出成功");
}
/**
* 用户注册
*/
// @ApiEncrypt
@PostMapping("/register")
@SaIgnore
public R<Void> register(@Validated @RequestBody RegisterBody user) {
// if (!configService.selectRegisterEnabled(user.getTenantId())) {
// return R.fail("当前系统没有开启注册功能!");
// }
registerService.register(user);
return R.ok();
}
/**
* 登录页面租户下拉框
*
* @return 租户列表
*/
@GetMapping("/tenant/list")
public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
// 返回对象
LoginTenantVo result = new LoginTenantVo();
boolean enable = TenantHelper.isEnable();
result.setTenantEnabled(enable);
// 如果未开启租户这直接返回
if (!enable) {
return R.ok(result);
}
List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo());
List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class);
try {
// 如果只超管返回所有租户
if (LoginHelper.isSuperAdmin()) {
result.setVoList(voList);
return R.ok(result);
}
} catch (NotLoginException ignored) {
}
// 获取域名
String host;
String referer = request.getHeader("referer");
if (StringUtils.isNotBlank(referer)) {
// 这里从referer中取值是为了本地使用hosts添加虚拟域名方便本地环境调试
host = referer.split("//")[1].split("/")[0];
} else {
host = new URL(request.getRequestURL().toString()).getHost();
}
// 根据域名进行筛选
List<TenantListVo> list = StreamUtils.filter(voList, vo ->
StringUtils.equalsIgnoreCase(vo.getDomain(), host));
result.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
return R.ok(result);
}
@SneakyThrows
@PostMapping("/wxLogin")
public ResponseEntity<WxLoginVo> wxLogin(@Valid @RequestBody UserLoginDTO userLoginDTO) {
String code = userLoginDTO.getCode();
try {
String requestUrl = loginUrl + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
URL url = new URL(requestUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
JSONObject jsonObject = JSONObject.parseObject(response.toString());
if (jsonObject.containsKey("openid") && jsonObject.containsKey("session_key")) {
String openid = jsonObject.getString("openid");
String sessionKey = jsonObject.getString("session_key");
String token = generateToken(openid, sessionKey);
WxLoginVo loginVo = new WxLoginVo();
loginVo.setOpenid(openid);
loginVo.setToken(token);
return ResponseEntity.ok(loginVo);
} else {
return ResponseEntity.badRequest().build();
}
} catch (IOException e) {
return ResponseEntity.internalServerError().build();
}
}
private String generateToken(String openid, String sessionKey) {
return openid + "_" + sessionKey;
}
@PostMapping("/wxRegister")
@SaIgnore
public R<Void> wxRegister(@RequestBody WxRegisterDTO wxRegisterDTO) {
registerService.WxRegister(wxRegisterDTO);
return R.ok();
}
@PostMapping("/getUserName")
@SaIgnore
public List<SysUserVo> getUserName() {
return userService.selectUserName();
}
@GetMapping("/autoLogin")
@SaIgnore
public ModelAndView autoLoginGet(@RequestParam("userId") Long userId, HttpServletResponse response) throws IOException {
// System.out.println("开始自动登录流程 - 用户ID: " + userId);
// 1. 查询用户
SysUserVo user = userService.selectUserByUserId(userId);
System.out.println("获取用户信息结果: " + (user != null ? "成功" : "失败"));
// System.out.println("用户信息: " + user);
// 2. 构建LoginUser
LoginUser loginUser = loginService.buildLoginUser(user);
loginUser.setClientKey("pc");
loginUser.setDeviceType("pc");
SaLoginModel model = new SaLoginModel();
model.setDevice("pc");
model.setTimeout(604800);
model.setActiveTimeout(1800);
model.setExtra(LoginHelper.CLIENT_KEY, "e5cd7e4891bf95d1d19206ce24a7b32e");
LoginHelper.login(loginUser, model);
String token = StpUtil.getTokenValue();
Cookie cookie = new Cookie("satoken", token);
cookie.setPath("/");
cookie.setMaxAge(604800);
response.addCookie(cookie);
response.setHeader("Authorization", "Bearer " + token);
// System.out.println("登录完成token: " + StpUtil.getTokenValue());
System.out.println("====进行跳转");
System.out.println("准备跳转到首页");
return new ModelAndView(new RedirectView("https://api.buzhiyushu.cn/reigsn?token=" + token));
}
@GetMapping("/test")
@SaIgnore
public ModelAndView test(HttpServletResponse response) throws IOException {
System.out.println("开始测试登录流程");
Long userId = 1L;
// 1. 查询用户
// 1. 查询用户
SysUserVo user = userService.selectUserByUserId(userId);
System.out.println("获取用户信息结果: " + (user != null ? "成功" : "失败"));
// System.out.println("用户信息: " + user);
// 2. 构建LoginUser
LoginUser loginUser = loginService.buildLoginUser(user);
loginUser.setClientKey("pc");
loginUser.setDeviceType("pc");
SaLoginModel model = new SaLoginModel();
model.setDevice("pc");
model.setTimeout(604800);
model.setActiveTimeout(1800);
model.setExtra(LoginHelper.CLIENT_KEY, "e5cd7e4891bf95d1d19206ce24a7b32e");
LoginHelper.login(loginUser, model);
String token = StpUtil.getTokenValue();
Cookie cookie = new Cookie("satoken", token);
cookie.setPath("/");
cookie.setMaxAge(604800);
response.addCookie(cookie);
response.setHeader("Authorization", "Bearer " + token);
// System.out.println("登录完成token: " + StpUtil.getTokenValue());
System.out.println("====进行跳转");
System.out.println("准备跳转到首页");
return new ModelAndView(new RedirectView("https://erp.buzhiyushu.cn/index?token=" + token));
}
}

View File

@ -0,0 +1,139 @@
package org.dromara.web.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import org.dromara.common.mail.config.properties.MailProperties;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.ratelimiter.annotation.RateLimiter;
import org.dromara.common.ratelimiter.enums.LimitType;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.common.web.enums.CaptchaType;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.web.domain.vo.CaptchaVo;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.util.LinkedHashMap;
/**
* 验证码操作处理
*
* @author Lion Li
*/
@SaIgnore
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@CrossOrigin(origins = "https://erp.newadmin.buzhiyushu.cn",maxAge = 3600)
public class CaptchaController {
private final CaptchaProperties captchaProperties;
private final MailProperties mailProperties;
/**
* 短信验证码
*
* @param phonenumber 用户手机号
*/
@RateLimiter(key = "#phonenumber", time = 60, count = 1)
@GetMapping("/resource/sms/code")
public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
// 验证码模板id 自行处理 (查数据库或写死均可)
String templateId = "";
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put("code", code);
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
if (!smsResponse.isSuccess()) {
log.error("验证码短信发送异常 => {}", smsResponse);
return R.fail(smsResponse.getData().toString());
}
return R.ok();
}
/**
* 邮箱验证码
*
* @param email 邮箱
*/
@RateLimiter(key = "#email", time = 60, count = 1)
@GetMapping("/resource/email/code")
public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
if (!mailProperties.getEnabled()) {
return R.fail("当前系统没有开启邮箱功能!");
}
String key = GlobalConstants.CAPTCHA_CODE_KEY + email;
String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
try {
MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
} catch (Exception e) {
log.error("验证码短信发送异常 => {}", e.getMessage());
return R.fail(e.getMessage());
}
return R.ok();
}
/**
* 生成验证码
*/
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
@GetMapping("/auth/code")
@SaIgnore
public R<CaptchaVo> getCode() {
CaptchaVo captchaVo = new CaptchaVo();
boolean captchaEnabled = captchaProperties.getEnable();
if (!captchaEnabled) {
captchaVo.setCaptchaEnabled(false);
return R.ok(captchaVo);
}
// 保存验证码信息
String uuid = IdUtil.simpleUUID();
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid;
// 生成验证码
CaptchaType captchaType = captchaProperties.getType();
boolean isMath = CaptchaType.MATH == captchaType;
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
captcha.setGenerator(codeGenerator);
captcha.createCode();
// 如果是数学验证码使用SpEL表达式处理验证码结果
String code = captcha.getCode();
if (isMath) {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
code = exp.getValue(String.class);
}
RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
captchaVo.setUuid(uuid);
captchaVo.setImg(captcha.getImageBase64());
return R.ok(captchaVo);
}
}

View File

@ -0,0 +1,25 @@
package org.dromara.web.domain.vo;
import lombok.Data;
import java.util.List;
/**
* 登录租户对象
*
* @author Michelle.Chung
*/
@Data
public class LoginTenantVo {
/**
* 租户开关
*/
private Boolean tenantEnabled;
/**
* 租户对象列表
*/
private List<TenantListVo> voList;
}

View File

@ -0,0 +1,31 @@
package org.dromara.web.domain.vo;
import org.dromara.system.domain.vo.SysTenantVo;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
/**
* 租户列表
*
* @author Lion Li
*/
@Data
@AutoMapper(target = SysTenantVo.class)
public class TenantListVo {
/**
* 租户编号
*/
private String tenantId;
/**
* 企业名称
*/
private String companyName;
/**
* 域名
*/
private String domain;
}

View File

@ -0,0 +1,12 @@
package org.dromara.web.domain.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class WxLoginVo {
private Long id;
private String openid;
private String token;
}

View File

@ -0,0 +1,16 @@
package org.dromara.web.domain.vo.dto;
import lombok.Data;
import org.dromara.common.core.domain.model.LoginBody;
@Data
public class WxRegisterDTO extends LoginBody {
private String username;
private String password;
private String userType;
/**
* 邀请码
*/
private String inviteCode;
}

View File

@ -0,0 +1,165 @@
package org.dromara.web.listener;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.domain.dto.UserOnlineDTO;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.ip.AddressUtils;
import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Component;
import java.time.Duration;
/**
* 用户行为 侦听器的实现
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Component
@Slf4j
public class UserActionListener implements SaTokenListener {
private final SaTokenConfig tokenConfig;
private final SysLoginService loginService;
/**
* 每次登录时触发
*/
@Override
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = ServletUtils.getClientIP();
UserOnlineDTO dto = new UserOnlineDTO();
dto.setIpaddr(ip);
dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
dto.setBrowser(userAgent.getBrowser().getName());
dto.setOs(userAgent.getOs().getName());
dto.setLoginTime(System.currentTimeMillis());
dto.setTokenId(tokenValue);
String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY);
String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY);
dto.setUserName(username);
dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY));
dto.setDeviceType(loginModel.getDevice());
dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY));
TenantHelper.dynamic(tenantId, () -> {
if(tokenConfig.getTimeout() == -1) {
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
} else {
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
}
});
// 记录登录日志
LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username);
logininforEvent.setStatus(Constants.LOGIN_SUCCESS);
logininforEvent.setMessage(MessageUtils.message("user.login.success"));
logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent);
// 更新登录信息
loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip);
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次注销时触发
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
});
log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次被踢下线时触发
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
});
log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次被顶下线时触发
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
});
log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次被封禁时触发
*/
@Override
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
}
/**
* 每次被解封时触发
*/
@Override
public void doUntieDisable(String loginType, Object loginId, String service) {
}
/**
* 每次打开二级认证时触发
*/
@Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
}
/**
* 每次创建Session时触发
*/
@Override
public void doCloseSafe(String loginType, String tokenValue, String service) {
}
/**
* 每次创建Session时触发
*/
@Override
public void doCreateSession(String id) {
}
/**
* 每次注销Session时触发
*/
@Override
public void doLogoutSession(String id) {
}
/**
* 每次Token续期时触发
*/
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
}
}

View File

@ -0,0 +1,49 @@
package org.dromara.web.service;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.web.domain.vo.LoginVo;
/**
* 授权策略
*
* @author Michelle.Chung
*/
public interface IAuthStrategy {
String BASE_NAME = "AuthStrategy";
/**
* 登录
*
* @param body 登录对象
* @param client 授权管理视图对象
* @param grantType 授权类型
* @return 登录验证信息
*/
static LoginVo login(String body, SysClientVo client, String grantType) {
// 授权类型和客户端id
if(grantType.equals("social")) {
grantType = "password";
}
String beanName = grantType + BASE_NAME;
if (!SpringUtils.containsBean(beanName)) {
throw new ServiceException("授权类型不正确!");
}
IAuthStrategy instance = SpringUtils.getBean(beanName);
return instance.login(body, client);
}
/**
* 登录
*
* @param body 登录对象
* @param client 授权管理视图对象
* @return 登录验证信息
*/
LoginVo login(String body, SysClientVo client);
}

View File

@ -0,0 +1,251 @@
package org.dromara.web.service;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.lock.annotation.Lock4j;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.dto.PostDTO;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.*;
import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.exception.TenantException;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysSocialBo;
import org.dromara.system.domain.vo.*;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.function.Supplier;
/**
* 登录校验方法
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Slf4j
@Service
public class SysLoginService {
@Value("${user.password.maxRetryCount}")
private Integer maxRetryCount;
@Value("${user.password.lockTime}")
private Integer lockTime;
private final ISysTenantService tenantService;
private final ISysPermissionService permissionService;
private final ISysSocialService sysSocialService;
private final ISysRoleService roleService;
private final ISysDeptService deptService;
private final ISysPostService postService;
private final SysUserMapper userMapper;
/**
* 绑定第三方用户
*
* @param authUserData 授权响应实体
*/
@Lock4j
public void socialRegister(AuthUser authUserData) {
String authId = authUserData.getSource() + authUserData.getUuid();
// 第三方用户信息
SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class);
BeanUtil.copyProperties(authUserData.getToken(), bo);
Long userId = LoginHelper.getUserId();
bo.setUserId(userId);
bo.setAuthId(authId);
bo.setOpenId(authUserData.getUuid());
bo.setUserName(authUserData.getUsername());
bo.setNickName(authUserData.getNickname());
List<SysSocialVo> checkList = sysSocialService.selectByAuthId(authId);
if (CollUtil.isNotEmpty(checkList)) {
throw new ServiceException("此三方账号已经被绑定!");
}
// 查询是否已经绑定用户
SysSocialBo params = new SysSocialBo();
params.setUserId(userId);
params.setSource(bo.getSource());
List<SysSocialVo> list = sysSocialService.queryList(params);
if (CollUtil.isEmpty(list)) {
// 没有绑定用户, 新增用户信息
sysSocialService.insertByBo(bo);
} else {
// 更新用户信息
bo.setId(list.get(0).getId());
sysSocialService.updateByBo(bo);
// 如果要绑定的平台账号已经被绑定过了 是否抛异常自行决断
// throw new ServiceException("此平台账号已经被绑定!");
}
}
/**
* 退出登录
*/
public void logout() {
try {
LoginUser loginUser = LoginHelper.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
return;
}
if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
// 超级管理员 登出清除动态租户
TenantHelper.clearDynamic();
}
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
} catch (NotLoginException ignored) {
} finally {
try {
StpUtil.logout();
} catch (NotLoginException ignored) {
}
}
}
/**
* 记录登录信息
*
* @param tenantId 租户ID
* @param username 用户名
* @param status 状态
* @param message 消息内容
*/
public void recordLogininfor(String tenantId, String username, String status, String message) {
LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username);
logininforEvent.setStatus(status);
logininforEvent.setMessage(message);
logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent);
}
/**
* 构建登录用户
*/
public LoginUser buildLoginUser(SysUserVo user) {
LoginUser loginUser = new LoginUser();
Long userId = user.getUserId();
loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(userId);
loginUser.setDeptId(user.getDeptId());
loginUser.setUsername(user.getUserName());
loginUser.setNickname(user.getNickName());
loginUser.setUserType(user.getUserType());
loginUser.setMenuPermission(permissionService.getMenuPermission(userId));
loginUser.setRolePermission(permissionService.getRolePermission(userId));
if (ObjectUtil.isNotNull(user.getDeptId())) {
Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
}
List<SysRoleVo> roles = roleService.selectRolesByUserId(userId);
List<SysPostVo> posts = postService.selectPostsByUserId(userId);
loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class));
return loginUser;
}
/**
* 记录登录信息
*
* @param userId 用户ID
*/
public void recordLoginInfo(Long userId, String ip) {
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(ip);
sysUser.setLoginDate(DateUtils.getNowDate());
sysUser.setUpdateBy(userId);
DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
}
/**
* 登录校验
*/
public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL;
// 获取用户登录错误次数默认为0 (可自定义限制策略 例如: key + username + ip)
int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
// 锁定时间内登录 则踢出
if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
}
if (supplier.get()) {
// 错误次数递增
errorNumber++;
RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
// 达到规定错误次数 则锁定登录
if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
} else {
// 未达到规定错误次数
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
throw new UserException(loginType.getRetryLimitCount(), errorNumber);
}
}
// 登录成功 清空错误次数
RedisUtils.deleteObject(errorKey);
}
/**
* 校验租户
*
* @param tenantId 租户ID
*/
public void checkTenant(String tenantId) {
if (!TenantHelper.isEnable()) {
return;
}
if (StringUtils.isBlank(tenantId)) {
throw new TenantException("tenant.number.not.blank");
}
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
return;
}
SysTenantVo tenant = tenantService.queryByTenantId(tenantId);
if (ObjectUtil.isNull(tenant)) {
log.info("登录租户:{} 不存在.", tenantId);
throw new TenantException("tenant.not.exists");
} else if (SystemConstants.DISABLE.equals(tenant.getStatus())) {
log.info("登录租户:{} 已被停用.", tenantId);
throw new TenantException("tenant.blocked");
} else if (ObjectUtil.isNotNull(tenant.getExpireTime())
&& new Date().after(tenant.getExpireTime())) {
log.info("登录租户:{} 已超过有效期.", tenantId);
throw new TenantException("tenant.expired");
}
}
}

View File

@ -0,0 +1,185 @@
package org.dromara.web.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.pdd.pop.sdk.common.util.JsonUtil;
import io.swagger.v3.core.util.Json;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.PasswordLoginBody;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.user.CaptchaException;
import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.zhishu.util.InterfaceUtils;
import org.dromara.zhishu.util.UrlUtil;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* 密码认证策略
*
* @author Michelle.Chung
*/
@Slf4j
@Service("password" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class PasswordAuthStrategy implements IAuthStrategy {
private final CaptchaProperties captchaProperties;
private final SysLoginService loginService;
private final SysUserMapper userMapper;
@Override
public LoginVo login(String body, SysClientVo client) {
PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class);
ValidatorUtils.validate(loginBody);
String tenantId = loginBody.getTenantId();
// String username = loginBody.getUsername();
String phoneNumber=loginBody.getPhoneNumber();
String password = loginBody.getPassword();
String code = loginBody.getCode();
String uuid = loginBody.getUuid();
boolean captchaEnabled = captchaProperties.getEnable();
// 验证码开关
if (captchaEnabled) {
// validateCaptcha(tenantId, username, code, uuid);
validateCaptcha(tenantId, phoneNumber, code, uuid);
}
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
// SysUserVo user = loadUserByUsername(username);
SysUserVo user = loadUserByPhone(phoneNumber);
// loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
loginService.checkLogin(LoginType.PASSWORD, tenantId, phoneNumber, () -> !BCrypt.checkpw(password, user.getPassword()));
// 此处可根据登录用户的数据不同 自行创建 loginUser
return loginService.buildLoginUser(user);
});
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
// 登录其他
Map newLoginMap = new HashMap();
newLoginMap.put("username",phoneNumber);
newLoginMap.put("password",password);
newLoginMap.put("about_id",loginUser.getUserId().toString());
String res = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/login/128",newLoginMap);
Map resMap = JsonUtil.transferToObj(res,Map.class);
if (resMap.get("msg") != null && resMap.get("msg").equals("用户不存在")){
Map employeeMap = new HashMap();
employeeMap.put("username",phoneNumber);
employeeMap.put("password",password);
employeeMap.put("about_id",loginUser.getUserId().toString());
employeeMap.put("fid","0");
employeeMap.put("name",phoneNumber);
employeeMap.put("phone",phoneNumber);
employeeMap.put("from","ERP");
String employeeRes = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/employee/reg",employeeMap);
Map employeeResMap = JsonUtil.transferToObj(employeeRes,Map.class);
if (employeeResMap.get("message") != null && employeeResMap.get("message").equals("添加成功")){
res = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/login/128",newLoginMap);
resMap = JsonUtil.transferToObj(res,Map.class);
if (resMap.get("msg") != null && resMap.get("msg").equals("登录成功")){
Map data = (Map) resMap.get("data");
loginUser.setWarehouseLoginUser(data);
}
}
}else if (resMap.get("msg") != null && resMap.get("msg").equals("登录成功")){
if (resMap.get("msg") != null && resMap.get("msg").equals("登录成功")){
Map data = (Map) resMap.get("data");
loginUser.setWarehouseLoginUser(data);
}
}
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token
LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
return loginVo;
}
/**
* 校验验证码
*
* @param username 用户名
* @param code 验证码
* @param uuid 唯一标识
*/
private void validateCaptcha(String tenantId, String username, String code, String uuid) {
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
String captcha = RedisUtils.getCacheObject(verifyKey);
RedisUtils.deleteObject(verifyKey);
if (captcha == null) {
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
}
if (!code.equalsIgnoreCase(captcha)) {
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
throw new CaptchaException();
}
}
private SysUserVo loadUserByUsername(String username) {
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new UserException("user.not.exists", username);
} else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new UserException("user.blocked", username);
}
return user;
}
// 新增方法
private SysUserVo loadUserByPhone(String username) {
// SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, username));
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
throw new UserException("user.not.exists", username);
} else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new UserException("user.blocked", username);
}
return user;
}
}

View File

@ -0,0 +1,131 @@
package org.dromara.web.service.impl;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysSocialVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysSocialService;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 第三方授权策略
*
* @author thiszhc is 三三
*/
@Slf4j
@Service("social" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class SocialAuthStrategy implements IAuthStrategy {
private final SocialProperties socialProperties;
private final ISysSocialService sysSocialService;
private final SysUserMapper userMapper;
private final SysLoginService loginService;
/**
* 登录-第三方授权登录
*
* @param body 登录信息
* @param client 客户端信息
*/
@Override
public LoginVo login(String body, SysClientVo client) {
SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class);
ValidatorUtils.validate(loginBody);
AuthResponse<AuthUser> response = SocialUtils.loginAuth(
loginBody.getSource(), loginBody.getSocialCode(),
loginBody.getSocialState(), socialProperties);
if (!response.ok()) {
throw new ServiceException(response.getMsg());
}
AuthUser authUserData = response.getData();
if ("GITEE".equals(authUserData.getSource())) {
// 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖
HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus")
.formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
.executeAsync();
HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus")
.formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
.executeAsync();
}
List<SysSocialVo> list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid());
if (CollUtil.isEmpty(list)) {
throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!");
}
SysSocialVo social;
if (TenantHelper.isEnable()) {
Optional<SysSocialVo> opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId()));
if (opt.isEmpty()) {
throw new ServiceException("对不起,你没有权限登录当前租户!");
}
social = opt.get();
} else {
social = list.get(0);
}
LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> {
SysUserVo user = loadUser(social.getUserId());
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user);
});
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token
LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
return loginVo;
}
private SysUserVo loadUser(Long userId) {
SysUserVo user = userMapper.selectVoById(userId);
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", "");
throw new UserException("user.not.exists", "");
} else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", "");
throw new UserException("user.blocked", "");
}
return user;
}
}

View File

@ -0,0 +1,153 @@
package org.dromara.web.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.XcxLoginBody;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysUserService;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service;
/**
* 小程序认证策略
*
* @author Michelle.Chung
*/
@Slf4j
@Service("xcx" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class XcxAuthStrategy implements IAuthStrategy {
private final SysLoginService loginService;
private final ISysUserService userService;
@Override
public LoginVo login(String body, SysClientVo client) {
XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
ValidatorUtils.validate(loginBody);
// xcxCode 小程序调用 wx.login 授权后获取
String xcxCode = loginBody.getXcxCode();
// 多个小程序识别使用
String appid = loginBody.getAppid();
// 参数校验
if (StringUtils.isBlank(appid) || StringUtils.isBlank(xcxCode)) {
throw new ServiceException("appid 或 xcxCode 不能为空");
}
// 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key openid
AuthRequest authRequest = new AuthWechatMiniProgramRequest(AuthConfig.builder()
.clientId(appid).clientSecret("c691dea9dfde1da7ae51c34f5a6d3d53")
.ignoreCheckRedirectUri(true).ignoreCheckState(true).build());
AuthCallback authCallback = new AuthCallback();
authCallback.setCode(xcxCode);
AuthResponse<AuthUser> resp = authRequest.login(authCallback);
String openid, unionId;
if (resp.ok()) {
AuthToken token = resp.getData().getToken();
openid = token.getOpenId();
// 微信小程序只有关联到微信开放平台下之后才能获取到 unionId因此unionId不一定能返回
unionId = token.getUnionId();
// openId 存到对应用户中
log.info("登录成功openid: {}, unionId: {}", openid, unionId);
} else {
log.error("微信小程序登录失败,错误信息: {}", resp.getMsg());
throw new ServiceException(resp.getMsg());
}
// 把openId存到对应用户中
String phoneNumber = loginBody.getPhoneNumber();
String password = loginBody.getPassword();
SysUserVo user1 = userService.selectUserByPhonenumber(phoneNumber);
// System.out.println("============="+user1);
if (user1 == null) {
log.error("用户手机号 {} 未找到对应的用户记录", phoneNumber);
throw new ServiceException("用户未找到对应的用户记录");
}
// 验证密码是否正确
if (!BCrypt.checkpw(password, user1.getPassword())) {
log.error("用户密码不正确");
throw new ServiceException("用户密码不正确");
}
// 检查 openId 是否为 null 或者不等于传入的 openid
String existingOpenId = user1.getOpenId();
if (existingOpenId == null || !existingOpenId.equals(openid)) {
// 如果 openId 不匹配则更新数据库中的 openId
userService.insertUserOpenId(openid, user1.getPhonenumber());
}
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
SysUserVo user = loadUserByOpenid(openid,loginBody.getPhoneNumber());
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
XcxLoginUser loginUser = new XcxLoginUser();
loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(user.getUserId());
loginUser.setUsername(user.getUserName());
loginUser.setNickname(user.getNickName());
loginUser.setUserType(user.getUserType());
loginUser.setPhoneNumber(user.getPhonenumber());
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
loginUser.setOpenid(openid);
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token
LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
loginVo.setOpenid(openid);
loginVo.setPhoneNumber(phoneNumber);
loginVo.setNickName(loginUser.getNickname());
loginVo.setUserId(user1.getUserId());
return loginVo;
}
private SysUserVo loadUserByOpenid(String openid, String phoneNumber) {
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
// todo 自行实现 userService.selectUserByOpenid(openid);
SysUserVo user = userService.selectUserByOpenid(openid,phoneNumber);
// SysUserVo user = new SysUserVo();
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", openid);
// todo 用户不存在 业务逻辑自行实现
} else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", openid);
// todo 用户已被停用 业务逻辑自行实现
}
return user;
}
}

View File

@ -0,0 +1,290 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
# RPC类型: netty, grpc
rpc-type: grpc
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源
master:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
# url: jdbc:mysql://111.229.25.150:3306/zhishu?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
url: jdbc:mysql://146.56.227.42:3306/zhishu?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: zhishu
password: XsRR4K3ATizyc5BK
# 腾讯云数据库
slave:
lazy: true
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://nj-cynosdbmysql-grp-1v6vxn5f.sql.tencentcdb.com:26247/task?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: Long6166@@
taskSlave:
lazy: true
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://36.212.12.247:3306/zhishu_slave?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: zhishu_slave
password: 7DpixiEdCs5p3PEr
psi:
lazy: true
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://175.27.224.66:3306/psi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: 5e07c0eec1770c94
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: 146.56.227.42
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# redis 密码必须配置
password: Qq123123
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称
clientName: ${ruoyi.name}
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方遵循RFC-822标准
from: xxx@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号
user: xxx@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长单位毫秒缺省值不超时
timeout: 0
# Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:80
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [openid, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
# zhishu业务配置
zhishu:
url: ./file/
filterUrl: ./file/fiter/
kfz-service-url: http://localhost:8095
history-shop-god-s-excel-file-path: D:\ShopGoodsData\HistoryGoodsData
new-shop-god-s-excel-file-path: D:\ShopGoodsData\NewShopGoodsData
changed-shop-god-s-excel-file-path: D:\ShopGoodsData\ChangedShopGoodsData
error-shop-god-s-excel-file-path: D:\ShopGoodsData\ErrorShopGoodsData

View File

@ -0,0 +1,317 @@
# 项目相关配置
ruoyi:
# 名称
name: ZhiShu
# 版本
version: ${revision}
# 版权年份
copyrightYear: 2024
# 配置IP地址
# ipurl: localhost:81
ipurl: erp.buzhiyushu.cn
# 邀请码配置
invite:
url:
# 邀请码链接前缀,需要修改为实际的前端注册页面地址
prefix: https://erp.buzhiyushu.cn/register?code=
captcha:
enable: true
# 页面 <参数设置> 可开启关闭 验证码校验
# 验证码类型 math 数组计算 char 字符验证
type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: CIRCLE
# 数字验证码位数
numberLength: 1
# 字符验证码长度
charLength: 4
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /
# undertow 配置
undertow:
# HTTP post内容的最大大小。当值为-1时默认值为大小是无限的zhishu/shopOrder/listByOrderSn
max-http-post-size: -1
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 512
# 是否分配的直接内存
direct-buffers: true
threads:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io: 8
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 256
# 日志配置
logging:
level:
org.dromara: @logging.level@
org.springframework: info
org.mybatis.spring.mapper: error
org.apache.fury: warn
config: classpath:logback-plus.xml
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间默认10分钟
lockTime: 10
# Spring配置
spring:
application:
name: ${ruoyi.name}
threads:
# 开启虚拟线程 仅jdk21可用
virtual:
enabled: false
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: @profiles.active@
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 30MB
# 设置总上传的文件大小
max-request-size: 100MB
mvc:
# 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/**
format:
date-time: yyyy-MM-dd HH:mm:ss
jackson:
# 日期格式化
date-format: yyyy-MM-dd HH:mm:ss
serialization:
# 格式化输出
indent_output: false
# 忽略无法转换的对象
fail_on_empty_beans: false
deserialization:
# 允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false
# jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz
# security配置
security:
# 排除路径
excludes:
- /*.html
- /**/*.html
- /**/*.css
- /**/*.js
- /favicon.ico
- /error
- /*/api-docs
- /*/api-docs/**
- /warm-flow-ui/token-name
# 多租户配置
tenant:
# 是否开启
enable: true
# 排除表
excludes:
- sys_menu
- sys_tenant
- sys_tenant_package
- sys_role_dept
- sys_role_menu
- sys_user_post
- sys_user_role
- sys_client
- sys_oss_config
- t_district
- t_invite_codes
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
# 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效
enableLogicDelete: true
# 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper
mapperPackage: org.dromara.**.mapper
# 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 实体扫描多个package用逗号或者分号分隔
typeAliasesPackage: org.dromara.**.domain
global-config:
dbConfig:
# 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
# 如需改为自增 需要将数据库表全部设置为自增
idType: ASSIGN_ID
# 是否开启MyBatis Plus sql执行日志
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 数据加密
mybatis-encryptor:
# 是否开启加密
enable: false
# 默认加密算法
algorithm: BASE64
# 编码方式 BASE64/HEX。默认BASE64
encode: BASE64
# 安全秘钥 对称算法的秘钥 如AESSM4
password:
# 公私钥 非对称算法的公私钥 如SM2RSA
publicKey:
privateKey:
# api接口加密
api-decrypt:
# 是否开启全局接口加密
enabled: true
# AES 加密头标识
headerFlag: encrypt-key
# 响应加密公钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换
# 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ==
# 请求解密私钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换
# 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
springdoc:
api-docs:
# 是否开启接口文档
enabled: true
# swagger-ui:
# # 持久化认证数据
# persistAuthorization: true
info:
# 标题
title: '标题:${ruoyi.name}多租户管理系统_接口文档'
# 描述
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
# 版本
version: '版本号: ${ruoyi.version}'
# 作者信息
contact:
name: Lion Li
email: crazylionli@163.com
url: https://gitee.com/dromara/RuoYi-Vue-Plus
components:
# 鉴权方式配置
security-schemes:
apiKey:
type: APIKEY
in: HEADER
name: ${sa-token.token-name}
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.演示模块
packages-to-scan: org.dromara.demo
- group: 2.通用模块
packages-to-scan: org.dromara.web
- group: 3.系统模块
packages-to-scan: org.dromara.system
- group: 4.代码生成模块
packages-to-scan: org.dromara.generator
- group: 5.工作流模块
packages-to-scan: org.dromara.workflow
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludeUrls:
- /system/notice
- /warm-flow/save-xml
# 全局线程池相关配置
# 如使用JDK21请直接使用虚拟线程 不要开启此配置
thread-pool:
# 是否开启线程池
enabled: false
# 队列最大长度
queueCapacity: 128
# 线程池维护线程所允许的空闲时间
keepAliveSeconds: 300
--- # 分布式锁 lock4j 全局配置
lock4j:
# 获取分布式锁超时时间,默认为 3000 毫秒
acquire-timeout: 3000
# 分布式锁的超时时间,默认为 30 秒
expire: 30000
--- # Actuator 监控端点的配置项
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS
logfile:
external-file: ./logs/sys-console.log
--- # 默认/推荐使用sse推送
sse:
enabled: true
path: /resource/sse
--- # websocket
websocket:
# 如果关闭 需要和前端开关一起关闭
enabled: false
# 路径
path: /resource/websocket
# 设置访问源地址
allowedOrigins: '*'
--- # warm-flow工作流配置
warm-flow:
# 是否开启工作流默认true
enabled: true
# 是否开启设计器ui
ui: true
# 默认Authorization如果有多个token用逗号分隔
token-name: ${sa-token.token-name},clientid
pdd:
app:
clientId: 203c5a7ba8bd4b8488d5e26f93052642
clientSecret: 892ffaa86e12b7a3d8d2942b669d9aa520ad8179
kongfz:
appId: 12345
appSecret: 4d9829df96cc9ec60b2754453e88fe3e68b187a1407c72774667aaf2b457c12a
accessToken: your_access_token_here
wechat:
appid: wx703b8fb6c3da692a
secret: c691dea9dfde1da7ae51c34f5a6d3d53
jscode2session-url: https://api.weixin.qq.com/sns/jscode2session
forest:
max-connections: 2000 # 连接池最大连接数
connect-timeout: 6000 # 连接超时时间,单位为毫秒
read-timeout: 6000 # 数据读取超时时间,单位为毫秒

View File

@ -0,0 +1,61 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=对不起, 您的账号:{0} 不存在.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号:{0} 已被删除
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.blank=用户名不能为空
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成且必须以非数字开头
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.register.save.error=保存用户 {0} 失败,注册账号已存在
user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
auth.grant.type.error=认证权限类型错误
auth.grant.type.blocked=认证权限类型已禁用
auth.grant.type.not.blank=认证权限类型不能为空
auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空
social.state.not.blank=第三方登录平台[state]不能为空
##租户
tenant.number.not.blank=租户编号不能为空
tenant.not.exists=对不起, 您的租户不存在,请联系管理员
tenant.blocked=对不起,您的租户已禁用,请联系管理员
tenant.expired=对不起,您的租户已过期,请联系管理员

View File

@ -0,0 +1,61 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=对不起, 您的账号:{0} 不存在.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号:{0} 已被删除
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.blank=用户名不能为空
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成且必须以非数字开头
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.register.save.error=保存用户 {0} 失败,注册账号已存在
user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
auth.grant.type.error=认证权限类型错误
auth.grant.type.blocked=认证权限类型已禁用
auth.grant.type.not.blank=认证权限类型不能为空
auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟
email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空
social.state.not.blank=第三方登录平台[state]不能为空
##租户
tenant.number.not.blank=租户编号不能为空
tenant.not.exists=对不起, 您的租户不存在,请联系管理员
tenant.blocked=对不起,您的租户已禁用,请联系管理员
tenant.expired=对不起,您的租户已过期,请联系管理员

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.zhishu.mapper.BookBaseInfoMapper">
<update id="updateByIllge">
UPDATE book_base_info
SET
vio_book = #{vioBook},
book_set = #{bookSet},
onenum_mbooks = #{onenumMbooks},
ill_publisher = #{illPublisher},
ill_author=#{illAuthor},
update_time = NOW()
WHERE id IN
<foreach collection="id" item="ids" open="(" separator="," close=")">
#{ids}
</foreach>
</update>
</mapper>

View File

@ -0,0 +1,45 @@
package org.dromara.test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* 断言单元测试案例
*
* @author Lion Li
*/
@DisplayName("断言单元测试案例")
public class AssertUnitTest {
@DisplayName("测试 assertEquals 方法")
@Test
public void testAssertEquals() {
Assertions.assertEquals("666", new String("666"));
Assertions.assertNotEquals("666", new String("666"));
}
@DisplayName("测试 assertSame 方法")
@Test
public void testAssertSame() {
Object obj = new Object();
Object obj1 = obj;
Assertions.assertSame(obj, obj1);
Assertions.assertNotSame(obj, obj1);
}
@DisplayName("测试 assertTrue 方法")
@Test
public void testAssertTrue() {
Assertions.assertTrue(true);
Assertions.assertFalse(true);
}
@DisplayName("测试 assertNull 方法")
@Test
public void testAssertNull() {
Assertions.assertNull(null);
Assertions.assertNotNull(null);
}
}

View File

@ -0,0 +1,72 @@
package org.dromara.test;
import org.dromara.common.core.enums.UserType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* 带参数单元测试案例
*
* @author Lion Li
*/
@DisplayName("带参数单元测试案例")
public class ParamUnitTest {
@DisplayName("测试 @ValueSource 注解")
@ParameterizedTest
@ValueSource(strings = {"t1", "t2", "t3"})
public void testValueSource(String str) {
System.out.println(str);
}
@DisplayName("测试 @NullSource 注解")
@ParameterizedTest
@NullSource
public void testNullSource(String str) {
System.out.println(str);
}
@DisplayName("测试 @EnumSource 注解")
@ParameterizedTest
@EnumSource(UserType.class)
public void testEnumSource(UserType type) {
System.out.println(type.getUserType());
}
@DisplayName("测试 @MethodSource 注解")
@ParameterizedTest
@MethodSource("getParam")
public void testMethodSource(String str) {
System.out.println(str);
}
public static Stream<String> getParam() {
List<String> list = new ArrayList<>();
list.add("t1");
list.add("t2");
list.add("t3");
return list.stream();
}
@BeforeEach
public void testBeforeEach() {
System.out.println("@BeforeEach ==================");
}
@AfterEach
public void testAfterEach() {
System.out.println("@AfterEach ==================");
}
}

View File

@ -0,0 +1 @@
3f2ee348-0303-40ca-bf03-03f48d2d2141

View File

@ -0,0 +1,4 @@
3
SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1
SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1
SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r

46
ruoyi-common/pom.xml Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>ruoyi-common-bom</module>
<module>ruoyi-common-social</module>
<module>ruoyi-common-core</module>
<module>ruoyi-common-doc</module>
<module>ruoyi-common-excel</module>
<module>ruoyi-common-idempotent</module>
<module>ruoyi-common-job</module>
<module>ruoyi-common-log</module>
<module>ruoyi-common-mail</module>
<module>ruoyi-common-mybatis</module>
<module>ruoyi-common-oss</module>
<module>ruoyi-common-ratelimiter</module>
<module>ruoyi-common-redis</module>
<module>ruoyi-common-satoken</module>
<module>ruoyi-common-security</module>
<module>ruoyi-common-sms</module>
<module>ruoyi-common-web</module>
<module>ruoyi-common-translation</module>
<module>ruoyi-common-sensitive</module>
<module>ruoyi-common-json</module>
<module>ruoyi-common-encrypt</module>
<module>ruoyi-common-tenant</module>
<module>ruoyi-common-websocket</module>
<module>ruoyi-common-sse</module>
</modules>
<artifactId>ruoyi-common</artifactId>
<packaging>pom</packaging>
<description>
common 通用模块
</description>
</project>

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-bom</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<description>
ruoyi-common-bom common依赖项
</description>
<properties>
<revision>5.3.0</revision>
</properties>
<dependencyManagement>
<dependencies>
<!-- 核心模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
<version>${revision}</version>
</dependency>
<!-- 接口模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
<version>${revision}</version>
</dependency>
<!-- excel -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-excel</artifactId>
<version>${revision}</version>
</dependency>
<!-- 幂等 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-idempotent</artifactId>
<version>${revision}</version>
</dependency>
<!-- 调度模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-job</artifactId>
<version>${revision}</version>
</dependency>
<!-- 日志记录 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-log</artifactId>
<version>${revision}</version>
</dependency>
<!-- 邮件服务 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
<version>${revision}</version>
</dependency>
<!-- 数据库服务 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mybatis</artifactId>
<version>${revision}</version>
</dependency>
<!-- OSS -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-oss</artifactId>
<version>${revision}</version>
</dependency>
<!-- 限流 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId>
<version>${revision}</version>
</dependency>
<!-- 缓存服务 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId>
<version>${revision}</version>
</dependency>
<!-- satoken -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-satoken</artifactId>
<version>${revision}</version>
</dependency>
<!-- 安全模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-security</artifactId>
<version>${revision}</version>
</dependency>
<!-- 短信模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sms</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId>
<version>${revision}</version>
</dependency>
<!-- web服务 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-web</artifactId>
<version>${revision}</version>
</dependency>
<!-- 翻译模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-translation</artifactId>
<version>${revision}</version>
</dependency>
<!-- 脱敏模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sensitive</artifactId>
<version>${revision}</version>
</dependency>
<!-- 序列化模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId>
<version>${revision}</version>
</dependency>
<!-- 数据库加解密模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-encrypt</artifactId>
<version>${revision}</version>
</dependency>
<!-- 租户模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-tenant</artifactId>
<version>${revision}</version>
</dependency>
<!-- WebSocket模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-websocket</artifactId>
<version>${revision}</version>
</dependency>
<!-- SSE模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sse</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-core</artifactId>
<description>
ruoyi-common-core 核心模块
</description>
<dependencies>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- servlet包 -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 自动生成YML配置关联JSON文件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
</dependency>
<!-- 离线IP地址定位库 -->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,17 @@
package org.dromara.common.core.config;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 程序注解配置
*
* @author Lion Li
*/
@AutoConfiguration
@EnableAspectJAutoProxy
@EnableAsync(proxyTargetClass = true)
public class ApplicationConfig {
}

View File

@ -0,0 +1,38 @@
package org.dromara.common.core.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* @author Lion Li
*/
@Data
@Component
@ConfigurationProperties(prefix = "ruoyi")
public class RuoYiConfig {
/**
* 项目名称
*/
private String name;
/**
* 版本
*/
private String version;
/**
* 版权年份
*/
private String copyrightYear;
/**
* 后台调用前台url
*/
private String ipurl;
}

View File

@ -0,0 +1,87 @@
package org.dromara.common.core.config;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.dromara.common.core.config.properties.ThreadPoolProperties;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.Threads;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.VirtualThreadTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置
*
* @author Lion Li
**/
@Slf4j
@AutoConfiguration
@EnableConfigurationProperties(ThreadPoolProperties.class)
public class ThreadPoolConfig {
/**
* 核心线程数 = cpu 核心数 + 1
*/
private final int core = Runtime.getRuntime().availableProcessors() + 1;
private ScheduledExecutorService scheduledExecutorService;
@Bean(name = "threadPoolTaskExecutor")
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(core);
executor.setMaxPoolSize(core * 2);
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
/**
* 执行周期性或定时任务
*/
@Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService() {
// daemon 必须为 true
BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder().daemon(true);
if (SpringUtils.isVirtual()) {
builder.namingPattern("virtual-schedule-pool-%d").wrappedFactory(new VirtualThreadTaskExecutor().getVirtualThreadFactory());
} else {
builder.namingPattern("schedule-pool-%d");
}
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core,
builder.build(),
new ThreadPoolExecutor.CallerRunsPolicy()) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
Threads.printException(r, t);
}
};
this.scheduledExecutorService = scheduledThreadPoolExecutor;
return scheduledThreadPoolExecutor;
}
/**
* 销毁事件
*/
@PreDestroy
public void destroy() {
try {
log.info("====关闭后台任务任务线程池====");
Threads.shutdownAndAwaitTermination(scheduledExecutorService);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,40 @@
package org.dromara.common.core.config;
import jakarta.validation.Validator;
import org.hibernate.validator.HibernateValidator;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import java.util.Properties;
/**
* 校验框架配置类
*
* @author Lion Li
*/
@AutoConfiguration
public class ValidatorConfig {
/**
* 配置校验框架 快速返回模式
*/
@Bean
public Validator validator(MessageSource messageSource) {
try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
// 国际化
factoryBean.setValidationMessageSource(messageSource);
// 设置使用 HibernateValidator 校验器
factoryBean.setProviderClass(HibernateValidator.class);
Properties properties = new Properties();
// 设置 快速异常返回
properties.setProperty("hibernate.validator.fail_fast", "true");
factoryBean.setValidationProperties(properties);
// 加载配置
factoryBean.afterPropertiesSet();
return factoryBean.getValidator();
}
}
}

View File

@ -0,0 +1,58 @@
package org.dromara.common.core.config;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.dromara.common.core.factory.YmlPropertySourceFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author: Sheldon Jia
* @ClassName: LoginConfig
* @Description: 登录功能配置项
* @date: 2025/05/04
*/
@Data
@Component
@ConfigurationProperties(prefix = "zhishu")
// @PropertySource(value = "classpath:base-${spring.profiles.active:dev}.yml", factory = YmlPropertySourceFactory.class)
public class ZhishuConfig {
/**
* url
*/
private String url;
/**
* filterUrl
*/
private String filterUrl;
/**
* kfz服务地址
*/
private String kfzServiceUrl;
/**
* 历史商品Excel文件目录地址
*/
private String historyShopGodSExcelFilePath;
/**
* 新增商品Excel文件暂存目录地址
*/
private String newShopGodSExcelFilePath;
/**
* 变更商品Excel文件暂存目录地址
*/
private String changedShopGodSExcelFilePath;
/**
* 异常商品Excel文件暂存目录地址
*/
private String errorShopGodSExcelFilePath;
}

View File

@ -0,0 +1,30 @@
package org.dromara.common.core.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 线程池 配置属性
*
* @author Lion Li
*/
@Data
@ConfigurationProperties(prefix = "thread-pool")
public class ThreadPoolProperties {
/**
* 是否开启线程池
*/
private boolean enabled;
/**
* 队列最大长度
*/
private int queueCapacity;
/**
* 线程池维护线程所允许的空闲时间
*/
private int keepAliveSeconds;
}

View File

@ -0,0 +1,30 @@
package org.dromara.common.core.constant;
/**
* 缓存的key 常量
*
* @author Lion Li
*/
public interface CacheConstants {
/**
* 在线用户 redis key
*/
String ONLINE_TOKEN_KEY = "online_tokens:";
/**
* 参数管理 cache key
*/
String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
String SYS_DICT_KEY = "sys_dict:";
/**
* 登录账户密码错误次数 redis key
*/
String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
}

View File

@ -0,0 +1,76 @@
package org.dromara.common.core.constant;
/**
* 通用常量信息
*
* @author ruoyi
*/
public interface Constants {
/**
* UTF-8 字符集
*/
String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
String GBK = "GBK";
/**
* www主域
*/
String WWW = "www.";
/**
* http请求
*/
String HTTP = "http://";
/**
* https请求
*/
String HTTPS = "https://";
/**
* 通用成功标识
*/
String SUCCESS = "0";
/**
* 通用失败标识
*/
String FAIL = "1";
/**
* 登录成功
*/
String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
String LOGOUT = "Logout";
/**
* 注册
*/
String REGISTER = "Register";
/**
* 登录失败
*/
String LOGIN_FAIL = "Error";
/**
* 验证码有效期分钟
*/
Integer CAPTCHA_EXPIRATION = 2;
/**
* 顶级父级id
*/
Long TOP_PARENT_ID = 0L;
}

View File

@ -0,0 +1,93 @@
package org.dromara.common.core.constant;
/**
* 返回状态码
*
* @author Lion Li
*/
public interface HttpStatus {
/**
* 操作成功
*/
int SUCCESS = 200;
/**
* 对象创建成功
*/
int CREATED = 201;
/**
* 请求已经被接受
*/
int ACCEPTED = 202;
/**
* 操作已经执行成功但是没有返回数据
*/
int NO_CONTENT = 204;
/**
* 资源已被移除
*/
int MOVED_PERM = 301;
/**
* 重定向
*/
int SEE_OTHER = 303;
/**
* 资源没有被修改
*/
int NOT_MODIFIED = 304;
/**
* 参数列表错误缺少格式不匹配
*/
int BAD_REQUEST = 400;
/**
* 未授权
*/
int UNAUTHORIZED = 401;
/**
* 访问受限授权过期
*/
int FORBIDDEN = 403;
/**
* 资源服务未找到
*/
int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
int BAD_METHOD = 405;
/**
* 资源冲突或者资源被锁
*/
int CONFLICT = 409;
/**
* 不支持的数据媒体类型
*/
int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
int ERROR = 500;
/**
* 接口未实现
*/
int NOT_IMPLEMENTED = 501;
/**
* 系统警告消息
*/
int WARN = 601;
}

View File

@ -0,0 +1,75 @@
package org.dromara.common.core.constant;
/**
* 系统常量信息
*
* @author Lion Li
*/
public interface SystemConstants {
/**
* 正常状态
*/
String NORMAL = "0";
/**
* 异常状态
*/
String DISABLE = "1";
/**
* 是否为系统默认
*/
String YES = "Y";
/**
* 是否为系统默认
*/
String NO = "N";
/**
* 是否菜单外链
*/
String YES_FRAME = "0";
/**
* 是否菜单外链
*/
String NO_FRAME = "1";
/**
* 菜单类型目录
*/
String TYPE_DIR = "M";
/**
* 菜单类型菜单
*/
String TYPE_MENU = "C";
/**
* 菜单类型按钮
*/
String TYPE_BUTTON = "F";
/**
* Layout组件标识
*/
String LAYOUT = "Layout";
/**
* ParentView组件标识
*/
String PARENT_VIEW = "ParentView";
/**
* InnerLink组件标识
*/
String INNER_LINK = "InnerLink";
/**
* 超级管理员ID
*/
Long SUPER_ADMIN_ID = 1L;
}

View File

@ -0,0 +1,35 @@
package org.dromara.common.core.constant;
/**
* 租户常量信息
*
* @author Lion Li
*/
public interface TenantConstants {
/**
* 超级管理员ID
*/
Long SUPER_ADMIN_ID = 1L;
/**
* 超级管理员角色 roleKey
*/
String SUPER_ADMIN_ROLE_KEY = "superadmin";
/**
* 租户管理员角色 roleKey
*/
String TENANT_ADMIN_ROLE_KEY = "admin";
/**
* 租户管理员角色名称
*/
String TENANT_ADMIN_ROLE_NAME = "管理员";
/**
* 默认租户ID
*/
String DEFAULT_TENANT_ID = "000000";
}

View File

@ -0,0 +1,110 @@
package org.dromara.common.core.domain;
import org.dromara.common.core.constant.HttpStatus;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 响应信息主体
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
public class R<T> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 成功
*/
public static final int SUCCESS = 200;
/**
* 失败
*/
public static final int FAIL = 500;
private int code;
private String msg;
private T data;
public static <T> R<T> ok() {
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data) {
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(String msg) {
return restResult(null, SUCCESS, msg);
}
public static <T> R<T> ok(String msg, T data) {
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail() {
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg) {
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data) {
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg, T data) {
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg) {
return restResult(null, code, msg);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static <T> R<T> warn(String msg) {
return restResult(null, HttpStatus.WARN, msg);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static <T> R<T> warn(String msg, T data) {
return restResult(data, HttpStatus.WARN, msg);
}
private static <T> R<T> restResult(T data, int code, String msg) {
R<T> r = new R<>();
r.setCode(code);
r.setData(data);
r.setMsg(msg);
return r;
}
public static <T> Boolean isError(R<T> ret) {
return !isSuccess(ret);
}
public static <T> Boolean isSuccess(R<T> ret) {
return R.SUCCESS == ret.getCode();
}
}

View File

@ -0,0 +1,71 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 办理任务请求对象
*
* @author may
*/
@Data
public class CompleteTaskDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务id
*/
private Long taskId;
/**
* 附件id
*/
private String fileId;
/**
* 抄送人员
*/
private List<FlowCopyDTO> flowCopyList;
/**
* 消息类型
*/
private List<String> messageType;
/**
* 办理意见
*/
private String message;
/**
* 消息通知
*/
private String notice;
/**
* 流程变量
*/
private Map<String, Object> variables;
/**
* 扩展变量(此处为逗号分隔的ossId)
*/
private String ext;
public Map<String, Object> getVariables() {
if (variables == null) {
return new HashMap<>(16);
}
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
return variables;
}
}

View File

@ -0,0 +1,30 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 抄送
*
* @author may
*/
@Data
public class FlowCopyDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 用户id
*/
private Long userId;
/**
* 用户名称
*/
private String userName;
}

View File

@ -0,0 +1,46 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* OSS对象
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
public class OssDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 对象存储主键
*/
private Long ossId;
/**
* 文件名
*/
private String fileName;
/**
* 原名
*/
private String originalName;
/**
* 文件后缀名
*/
private String fileSuffix;
/**
* URL地址
*/
private String url;
}

View File

@ -0,0 +1,42 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 角色
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
public class RoleDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 角色ID
*/
private Long roleId;
/**
* 角色名称
*/
private String roleName;
/**
* 角色权限
*/
private String roleKey;
/**
* 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限
*/
private String dataScope;
}

View File

@ -0,0 +1,30 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 启动流程返回对象
*
* @author Lion Li
*/
@Data
public class StartProcessReturnDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 流程实例id
*/
private Long processInstanceId;
/**
* 任务id
*/
private Long taskId;
}

View File

@ -0,0 +1,101 @@
package org.dromara.common.core.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 任务受让人
*
* @author AprilWind
*/
@Data
@NoArgsConstructor
public class TaskAssigneeDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 总大小
*/
private Long total = 0L;
/**
*
*/
private List<TaskHandler> list;
public TaskAssigneeDTO(Long total, List<TaskHandler> list) {
this.total = total;
this.list = list;
}
/**
* 将源列表转换为 TaskHandler 列表
*
* @param <T> 通用类型
* @param sourceList 待转换的源列表
* @param storageId 提取 storageId 的函数
* @param handlerCode 提取 handlerCode 的函数
* @param handlerName 提取 handlerName 的函数
* @param groupName 提取 groupName 的函数
* @param createTimeMapper 提取 createTime 的函数
* @return 转换后的 TaskHandler 列表
*/
public static <T> List<TaskHandler> convertToHandlerList(
List<T> sourceList,
Function<T, Long> storageId,
Function<T, String> handlerCode,
Function<T, String> handlerName,
Function<T, Long> groupName,
Function<T, Date> createTimeMapper) {
return sourceList.stream()
.map(item -> new TaskHandler(
String.valueOf(storageId.apply(item)),
handlerCode.apply(item),
handlerName.apply(item),
groupName != null ? String.valueOf(groupName.apply(item)) : null,
createTimeMapper.apply(item)
)).collect(Collectors.toList());
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class TaskHandler {
/**
* 主键
*/
private String storageId;
/**
* 权限编码
*/
private String handlerCode;
/**
* 权限名称
*/
private String handlerName;
/**
* 权限分组
*/
private String groupName;
/**
* 创建时间
*/
private Date createTime;
}
}

View File

@ -0,0 +1,72 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 当前在线会话
*
* @author ruoyi
*/
@Data
@NoArgsConstructor
public class UserOnlineDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 会话编号
*/
private String tokenId;
/**
* 部门名称
*/
private String deptName;
/**
* 用户名称
*/
private String userName;
/**
* 客户端
*/
private String clientKey;
/**
* 设备类型
*/
private String deviceType;
/**
* 登录IP地址
*/
private String ipaddr;
/**
* 登录地址
*/
private String loginLocation;
/**
* 浏览器类型
*/
private String browser;
/**
* 操作系统
*/
private String os;
/**
* 登录时间
*/
private Long loginTime;
}

View File

@ -0,0 +1,44 @@
package org.dromara.common.core.domain.event;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 流程办理监听
*
* @author may
*/
@Data
public class ProcessTaskEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 租户ID
*/
private String tenantId;
/**
* 流程定义编码
*/
private String flowCode;
/**
* 审批节点编码
*/
private String nodeCode;
/**
* 任务id
*/
private Long taskId;
/**
* 业务id
*/
private String businessId;
}

View File

@ -0,0 +1,31 @@
package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 邮件登录对象
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class EmailLoginBody extends LoginBody {
/**
* 邮箱
*/
@NotBlank(message = "{user.email.not.blank}")
@Email(message = "{user.email.not.valid}")
private String email;
/**
* 邮箱code
*/
@NotBlank(message = "{email.code.not.blank}")
private String emailCode;
}

View File

@ -0,0 +1,14 @@
package org.dromara.common.core.domain.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class InterfaceLoginBody extends LoginBody {
/**
* 用户密码
*/
private String password;
}

View File

@ -0,0 +1,66 @@
package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 用户登录对象
*
* @author Lion Li
*/
@Data
public class LoginBody implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 客户端id
*/
@NotBlank(message = "{auth.clientid.not.blank}")
private String clientId;
/**
* 授权类型
*/
@NotBlank(message = "{auth.grant.type.not.blank}")
private String grantType;
/**
* 租户ID
*/
private String tenantId;
/**
* 验证码
*/
private String code;
/**
* 唯一标识
*/
private String uuid;
private String phoneNumber;
/**
* 用户名
*/
private String userName;
/**
* longinCode
*/
private String login_code;
/**
* token
*/
private String token;
}

View File

@ -0,0 +1,153 @@
package org.dromara.common.core.domain.model;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.common.core.domain.dto.PostDTO;
import org.dromara.common.core.domain.dto.RoleDTO;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 登录用户身份权限
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
public class LoginUser implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 租户ID
*/
private String tenantId;
/**
* 用户ID
*/
private Long userId;
/**
* 部门ID
*/
private Long deptId;
/**
* 部门类别编码
*/
private String deptCategory;
/**
* 部门名
*/
private String deptName;
/**
* 用户唯一标识
*/
private String token;
/**
* 用户类型
*/
private String userType;
/**
* 登录时间
*/
private Long loginTime;
/**
* 过期时间
*/
private Long expireTime;
/**
* 登录IP地址
*/
private String ipaddr;
/**
* 登录地点
*/
private String loginLocation;
/**
* 浏览器类型
*/
private String browser;
/**
* 操作系统
*/
private String os;
/**
* 菜单权限
*/
private Set<String> menuPermission;
/**
* 角色权限
*/
private Set<String> rolePermission;
/**
* 用户名
*/
private String username;
/**
* 用户昵称
*/
private String nickname;
/**
* 角色对象
*/
private List<RoleDTO> roles;
/**
* 岗位对象
*/
private List<PostDTO> posts;
/**
* 数据权限 当前角色ID
*/
private Long roleId;
/**
* 客户端
*/
private String clientKey;
/**
* 设备类型
*/
private String deviceType;
/**
* 新仓库系统登录信息
*/
private Map warehouseLoginUser;
/**
* 获取登录id
*/
public String getLoginId() {
if (userType == null) {
throw new IllegalArgumentException("用户类型不能为空");
}
if (userId == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
return userType + ":" + userId;
}
}

View File

@ -0,0 +1,29 @@
package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 短信登录对象
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SmsLoginBody extends LoginBody {
/**
* 手机号
*/
@NotBlank(message = "{user.phonenumber.not.blank}")
private String phonenumber;
/**
* 短信code
*/
@NotBlank(message = "{sms.code.not.blank}")
private String smsCode;
}

View File

@ -0,0 +1,35 @@
package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 三方登录对象
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SocialLoginBody extends LoginBody {
/**
* 第三方登录平台
*/
@NotBlank(message = "{social.source.not.blank}")
private String source;
/**
* 第三方登录code
*/
@NotBlank(message = "{social.code.not.blank}")
private String socialCode;
/**
* 第三方登录socialState
*/
@NotBlank(message = "{social.state.not.blank}")
private String socialState;
}

View File

@ -0,0 +1,56 @@
package org.dromara.common.core.domain.model;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 任务受让人
*
* @author AprilWind
*/
@Data
@NoArgsConstructor
public class TaskAssigneeBody implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 权限编码
*/
private String handlerCode;
/**
* 权限名称
*/
private String handlerName;
/**
* 权限分组
*/
private String groupId;
/**
* 开始时间
*/
private String beginTime;
/**
* 结束时间
*/
private String endTime;
/**
* 当前页
*/
private Integer pageNum = 1;
/**
* 每页显示条数
*/
private Integer pageSize = 10;
}

View File

@ -0,0 +1,37 @@
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 设备类型
* 针对一套 用户体系
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum DeviceType {
/**
* pc端
*/
PC("pc"),
/**
* app端
*/
APP("app"),
/**
* 小程序端
*/
XCX("xcx"),
/**
* social第三方端
*/
SOCIAL("social");
private final String device;
}

View File

@ -0,0 +1,44 @@
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum LoginType {
/**
* 密码登录
*/
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
/**
* 短信登录
*/
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
/**
* 邮箱登录
*/
EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
/**
* 小程序登录
*/
XCX("", "");
/**
* 登录重试超出限制提示
*/
final String retryLimitExceed;
/**
* 登录重试限制计数提示
*/
final String retryLimitCount;
}

View File

@ -0,0 +1,30 @@
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户状态
*
* @author ruoyi
*/
@Getter
@AllArgsConstructor
public enum UserStatus {
/**
* 正常
*/
OK("0", "正常"),
/**
* 停用
*/
DISABLE("1", "停用"),
/**
* 删除
*/
DELETED("2", "删除");
private final String code;
private final String info;
}

View File

@ -0,0 +1,37 @@
package org.dromara.common.core.enums;
import org.dromara.common.core.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 设备类型
* 针对多套 用户体系
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum UserType {
/**
* pc端
*/
SYS_USER("sys_user"),
/**
* app端
*/
APP_USER("app_user");
private final String userType;
public static UserType getUserType(String str) {
for (UserType value : values()) {
if (StringUtils.contains(str, value.getUserType())) {
return value;
}
}
throw new RuntimeException("'UserType' not found By " + str);
}
}

View File

@ -0,0 +1,59 @@
package org.dromara.common.core.exception;
import lombok.*;
import java.io.Serial;
/**
* 业务异常
*
* @author ruoyi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public final class ServiceException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细内部调试错误
*/
private String detailMessage;
public ServiceException(String message) {
this.message = message;
}
public ServiceException(String message, Integer code) {
this.message = message;
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public ServiceException setMessage(String message) {
this.message = message;
return this;
}
public ServiceException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
}

View File

@ -0,0 +1,62 @@
package org.dromara.common.core.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
/**
* sse 特制异常
*
* @author LionLi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public final class SseException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细内部调试错误
*/
private String detailMessage;
public SseException(String message) {
this.message = message;
}
public SseException(String message, Integer code) {
this.message = message;
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public SseException setMessage(String message) {
this.message = message;
return this;
}
public SseException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
}

View File

@ -0,0 +1,18 @@
package org.dromara.common.core.exception.file;
import java.io.Serial;
/**
* 文件名称超长限制异常类
*
* @author ruoyi
*/
public class FileNameLengthLimitExceededException extends FileException {
@Serial
private static final long serialVersionUID = 1L;
public FileNameLengthLimitExceededException(int defaultFileNameLength) {
super("upload.filename.exceed.length", new Object[]{defaultFileNameLength});
}
}

View File

@ -0,0 +1,18 @@
package org.dromara.common.core.exception.file;
import java.io.Serial;
/**
* 文件名大小限制异常类
*
* @author ruoyi
*/
public class FileSizeLimitExceededException extends FileException {
@Serial
private static final long serialVersionUID = 1L;
public FileSizeLimitExceededException(long defaultMaxSize) {
super("upload.exceed.maxSize", new Object[]{defaultMaxSize});
}
}

View File

@ -0,0 +1,18 @@
package org.dromara.common.core.exception.user;
import java.io.Serial;
/**
* 验证码错误异常类
*
* @author ruoyi
*/
public class CaptchaException extends UserException {
@Serial
private static final long serialVersionUID = 1L;
public CaptchaException() {
super("user.jcaptcha.error");
}
}

View File

@ -0,0 +1,18 @@
package org.dromara.common.core.exception.user;
import java.io.Serial;
/**
* 验证码失效异常类
*
* @author ruoyi
*/
public class CaptchaExpireException extends UserException {
@Serial
private static final long serialVersionUID = 1L;
public CaptchaExpireException() {
super("user.jcaptcha.expire");
}
}

View File

@ -0,0 +1,20 @@
package org.dromara.common.core.exception.user;
import org.dromara.common.core.exception.base.BaseException;
import java.io.Serial;
/**
* 用户信息异常类
*
* @author ruoyi
*/
public class UserException extends BaseException {
@Serial
private static final long serialVersionUID = 1L;
public UserException(String code, Object... args) {
super("user", code, args, null);
}
}

View File

@ -0,0 +1,18 @@
package org.dromara.common.core.service;
/**
* 通用 参数配置服务
*
* @author Lion Li
*/
public interface ConfigService {
/**
* 根据参数 key 获取参数值
*
* @param configKey 参数 key
* @return 参数值
*/
String getConfigValue(String configKey);
}

View File

@ -0,0 +1,37 @@
package org.dromara.common.core.service;
import org.dromara.common.core.domain.dto.DeptDTO;
import java.util.List;
/**
* 通用 部门服务
*
* @author Lion Li
*/
public interface DeptService {
/**
* 通过部门ID查询部门名称
*
* @param deptIds 部门ID串逗号分隔
* @return 部门名称串逗号分隔
*/
String selectDeptNameByIds(String deptIds);
/**
* 根据部门ID查询部门负责人
*
* @param deptId 部门ID用于指定需要查询的部门
* @return 返回该部门的负责人ID
*/
Long selectDeptLeaderById(Long deptId);
/**
* 查询部门
*
* @return 部门列表
*/
List<DeptDTO> selectDeptsByList();
}

View File

@ -0,0 +1,29 @@
package org.dromara.common.core.service;
import org.dromara.common.core.domain.dto.OssDTO;
import java.util.List;
/**
* 通用 OSS服务
*
* @author Lion Li
*/
public interface OssService {
/**
* 通过ossId查询对应的url
*
* @param ossIds ossId串逗号分隔
* @return url串逗号分隔
*/
String selectUrlByIds(String ossIds);
/**
* 通过ossId查询列表
*
* @param ossIds ossId串逗号分隔
* @return 列表
*/
List<OssDTO> selectByIds(String ossIds);
}

View File

@ -0,0 +1,10 @@
package org.dromara.common.core.service;
/**
* 通用 岗位服务
*
* @author AprilWind
*/
public interface PostService {
}

View File

@ -0,0 +1,10 @@
package org.dromara.common.core.service;
/**
* 通用 角色服务
*
* @author AprilWind
*/
public interface RoleService {
}

View File

@ -0,0 +1,299 @@
package org.dromara.common.core.utils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.dromara.common.core.enums.FormatsType;
import org.dromara.common.core.exception.ServiceException;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* 时间工具类
*
* @author ruoyi
*/
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
private static final String[] PARSE_PATTERNS = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
@Deprecated
private DateUtils() {
}
/**
* 获取当前日期和时间
*
* @return 当前日期和时间的 Date 对象表示
*/
public static Date getNowDate() {
return new Date();
}
/**
* 获取当前日期的字符串表示格式为YYYY-MM-DD
*
* @return 当前日期的字符串表示
*/
public static String getDate() {
return dateTimeNow(FormatsType.YYYY_MM_DD);
}
/**
* 获取当前日期的字符串表示格式为yyyyMMdd
*
* @return 当前日期的字符串表示
*/
public static String getCurrentDate() {
return DateFormatUtils.format(new Date(), FormatsType.YYYYMMDD.getTimeFormat());
}
/**
* 获取当前日期的路径格式字符串格式为"yyyy/MM/dd"
*
* @return 当前日期的路径格式字符串
*/
public static String datePath() {
Date now = new Date();
return DateFormatUtils.format(now, FormatsType.YYYY_MM_DD_SLASH.getTimeFormat());
}
/**
* 获取当前时间的字符串表示格式为YYYY-MM-DD HH:MM:SS
*
* @return 当前时间的字符串表示
*/
public static String getTime() {
return dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS);
}
/**
* 获取当前时间的字符串表示格式为 "HH:MM:SS"
*
* @return 当前时间的字符串表示格式为 "HH:MM:SS"
*/
public static String getTimeWithHourMinuteSecond() {
return dateTimeNow(FormatsType.HH_MM_SS);
}
/**
* 获取当前日期和时间的字符串表示格式为YYYYMMDDHHMMSS
*
* @return 当前日期和时间的字符串表示
*/
public static String dateTimeNow() {
return dateTimeNow(FormatsType.YYYYMMDDHHMMSS);
}
public static String dataYMD(){
return dateTimeNow(FormatsType.YYYY_MM_DD);
}
/**
* 获取当前日期和时间的指定格式的字符串表示
*
* @param format 日期时间格式例如"YYYY-MM-DD HH:MM:SS"
* @return 当前日期和时间的字符串表示
*/
public static String dateTimeNow(final FormatsType format) {
return parseDateToStr(format, new Date());
}
/**
* 将指定日期格式化为 YYYY-MM-DD 格式的字符串
*
* @param date 要格式化的日期对象
* @return 格式化后的日期字符串
*/
public static String formatDate(final Date date) {
return parseDateToStr(FormatsType.YYYY_MM_DD, date);
}
/**
* 将指定日期格式化为 YYYY-MM-DD HH:MM:SS 格式的字符串
*
* @param date 要格式化的日期对象
* @return 格式化后的日期时间字符串
*/
public static String formatDateTime(final Date date) {
return parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, date);
}
/**
* 将指定日期按照指定格式进行格式化
*
* @param format 要使用的日期时间格式例如"YYYY-MM-DD HH:MM:SS"
* @param date 要格式化的日期对象
* @return 格式化后的日期时间字符串
*/
public static String parseDateToStr(final FormatsType format, final Date date) {
return new SimpleDateFormat(format.getTimeFormat()).format(date);
}
/**
* 将指定格式的日期时间字符串转换为 Date 对象
*
* @param format 要解析的日期时间格式例如"YYYY-MM-DD HH:MM:SS"
* @param ts 要解析的日期时间字符串
* @return 解析后的 Date 对象
* @throws RuntimeException 如果解析过程中发生异常
*/
public static Date parseDateTime(final FormatsType format, final String ts) {
try {
return new SimpleDateFormat(format.getTimeFormat()).parse(ts);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* 将对象转换为日期对象
*
* @param str 要转换的对象通常是字符串
* @return 转换后的日期对象如果转换失败或输入为null则返回null
*/
public static Date parseDate(Object str) {
if (str == null) {
return null;
}
try {
return parseDate(str.toString(), PARSE_PATTERNS);
} catch (ParseException e) {
return null;
}
}
/**
* 获取服务器启动时间
*
* @return 服务器启动时间的 Date 对象表示
*/
public static Date getServerStartDate() {
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}
/**
* 计算两个日期之间的天数差以毫秒为单位
*
* @param date1 第一个日期
* @param date2 第二个日期
* @return 两个日期之间的天数差的绝对值
*/
public static int differentDaysByMillisecond(Date date1, Date date2) {
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
}
/**
* 计算两个日期之间的时间差并以天小时和分钟的格式返回
*
* @param endDate 结束日期
* @param nowDate 当前日期
* @return 表示时间差的字符串格式为"天 小时 分钟"
*/
public static String getDatePoor(Date endDate, Date nowDate) {
long diffInMillis = endDate.getTime() - nowDate.getTime();
long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
return String.format("%d天 %d小时 %d分钟", day, hour, min);
}
/**
* 计算两个时间点的差值小时分钟当值为0时不显示该单位
*
* @param endDate 结束时间
* @param nowDate 当前时间
* @return 时间差字符串格式为 "x天 x小时 x分钟 x秒"若为 0 则不显示
*/
public static String getTimeDifference(Date endDate, Date nowDate) {
long diffInMillis = endDate.getTime() - nowDate.getTime();
long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
long sec = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
// 构建时间差字符串条件是值不为0才显示
StringBuilder result = new StringBuilder();
if (day > 0) {
result.append(String.format("%d天 ", day));
}
if (hour > 0) {
result.append(String.format("%d小时 ", hour));
}
if (min > 0) {
result.append(String.format("%d分钟 ", min));
}
if (sec > 0) {
result.append(String.format("%d秒", sec));
}
return result.length() > 0 ? result.toString().trim() : "0秒";
}
/**
* LocalDateTime 对象转换为 Date 对象
*
* @param temporalAccessor 要转换的 LocalDateTime 对象
* @return 转换后的 Date 对象
*/
public static Date toDate(LocalDateTime temporalAccessor) {
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
/**
* LocalDate 对象转换为 Date 对象
*
* @param temporalAccessor 要转换的 LocalDate 对象
* @return 转换后的 Date 对象
*/
public static Date toDate(LocalDate temporalAccessor) {
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
/**
* 校验日期范围
*
* @param startDate 开始日期
* @param endDate 结束日期
* @param maxValue 最大时间跨度的限制值
* @param unit 时间跨度的单位可选择 "DAYS""HOURS" "MINUTES"
*/
public static void validateDateRange(Date startDate, Date endDate, int maxValue, TimeUnit unit) {
// 校验结束日期不能早于开始日期
if (endDate.before(startDate)) {
throw new ServiceException("结束日期不能早于开始日期");
}
// 计算时间跨度
long diffInMillis = endDate.getTime() - startDate.getTime();
// 根据单位转换时间跨度
long diff = switch (unit) {
case DAYS -> TimeUnit.MILLISECONDS.toDays(diffInMillis);
case HOURS -> TimeUnit.MILLISECONDS.toHours(diffInMillis);
case MINUTES -> TimeUnit.MILLISECONDS.toMinutes(diffInMillis);
default -> throw new IllegalArgumentException("不支持的时间单位");
};
// 校验时间跨度不超过最大限制
if (diff > maxValue) {
throw new ServiceException("最大时间跨度为 " + maxValue + " " + unit.toString().toLowerCase());
}
}
/**
* 获取当前时间+1天的时间
* @return
*/
public static Date getNextDay() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return DateUtils.parseDateTime(FormatsType.YYYY_MM_DD_HH_MM_SS,df.format(new Date().getTime()+1*24*3600*1000));
}
}

View File

@ -0,0 +1,33 @@
package org.dromara.common.core.utils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.i18n.LocaleContextHolder;
/**
* 获取i18n资源文件
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MessageUtils {
private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class);
/**
* 根据消息键和参数 获取消息 委托给spring messageSource
*
* @param code 消息键
* @param args 参数
* @return 获取国际化翻译值
*/
public static String message(String code, Object... args) {
try {
return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
} catch (NoSuchMessageException e) {
return code;
}
}
}

View File

@ -0,0 +1,289 @@
package org.dromara.common.core.utils;
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* 客户端工具类提供获取请求参数响应处理头部信息等常用操作
*
* @author ruoyi
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ServletUtils extends JakartaServletUtil {
/**
* 获取指定名称的 String 类型的请求参数
*
* @param name 参数名
* @return 参数值
*/
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 获取指定名称的 String 类型的请求参数若参数不存在则返回默认值
*
* @param name 参数名
* @param defaultValue 默认值
* @return 参数值或默认值
*/
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取指定名称的 Integer 类型的请求参数
*
* @param name 参数名
* @return 参数值
*/
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取指定名称的 Integer 类型的请求参数若参数不存在则返回默认值
*
* @param name 参数名
* @param defaultValue 默认值
* @return 参数值或默认值
*/
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取指定名称的 Boolean 类型的请求参数
*
* @param name 参数名
* @return 参数值
*/
public static Boolean getParameterToBool(String name) {
return Convert.toBool(getRequest().getParameter(name));
}
/**
* 获取指定名称的 Boolean 类型的请求参数若参数不存在则返回默认值
*
* @param name 参数名
* @param defaultValue 默认值
* @return 参数值或默认值
*/
public static Boolean getParameterToBool(String name, Boolean defaultValue) {
return Convert.toBool(getRequest().getParameter(name), defaultValue);
}
/**
* 获取所有请求参数 Map 的形式返回
*
* @param request 请求对象{@link ServletRequest}
* @return 请求参数的 Map键为参数名值为参数值数组
*/
public static Map<String, String[]> getParams(ServletRequest request) {
final Map<String, String[]> map = request.getParameterMap();
return Collections.unmodifiableMap(map);
}
/**
* 获取所有请求参数 Map 的形式返回值为字符串形式的拼接
*
* @param request 请求对象{@link ServletRequest}
* @return 请求参数的 Map键为参数名值为拼接后的字符串
*/
public static Map<String, String> getParamMap(ServletRequest request) {
Map<String, String> params = new HashMap<>();
for (Map.Entry<String, String[]> entry : getParams(request).entrySet()) {
params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR));
}
return params;
}
/**
* 获取当前 HTTP 请求对象
*
* @return 当前 HTTP 请求对象
*/
public static HttpServletRequest getRequest() {
try {
return getRequestAttributes().getRequest();
} catch (Exception e) {
return null;
}
}
/**
* 获取当前 HTTP 响应对象
*
* @return 当前 HTTP 响应对象
*/
public static HttpServletResponse getResponse() {
try {
return getRequestAttributes().getResponse();
} catch (Exception e) {
return null;
}
}
/**
* 获取当前请求的 HttpSession 对象
* <p>
* 如果当前请求已经关联了一个会话即已经存在有效的 session ID
* 则返回该会话对象如果没有关联会话则会创建一个新的会话对象并返回
* <p>
* HttpSession 用于存储会话级别的数据如用户登录信息购物车内容等
* 可以在多个请求之间共享会话数据
*
* @return 当前请求的 HttpSession 对象
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
/**
* 获取当前请求的请求属性
*
* @return {@link ServletRequestAttributes} 请求属性对象
*/
public static ServletRequestAttributes getRequestAttributes() {
try {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
} catch (Exception e) {
return null;
}
}
/**
* 获取指定请求头的值如果头部为空则返回空字符串
*
* @param request 请求对象
* @param name 头部名称
* @return 头部值
*/
public static String getHeader(HttpServletRequest request, String name) {
String value = request.getHeader(name);
if (StringUtils.isEmpty(value)) {
return StringUtils.EMPTY;
}
return urlDecode(value);
}
/**
* 获取所有请求头的 Map键为头部名称值为头部值
*
* @param request 请求对象
* @return 请求头的 Map
*/
public static Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedCaseInsensitiveMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
}
return map;
}
/**
* 将字符串渲染到客户端 JSON 格式返回
*
* @param response 渲染对象
* @param string 待渲染的字符串
*/
public static void renderString(HttpServletResponse response, String string) {
try {
response.setStatus(HttpStatus.HTTP_OK);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 判断当前请求是否为 Ajax 异步请求
*
* @param request 请求对象
* @return 是否为 Ajax 请求
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
// 判断 Accept 头部是否包含 application/json
String accept = request.getHeader("accept");
if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) {
return true;
}
// 判断 X-Requested-With 头部是否包含 XMLHttpRequest
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
return true;
}
// 判断 URI 后缀是否为 .json .xml
String uri = request.getRequestURI();
if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) {
return true;
}
// 判断请求参数 __ajax 是否为 json xml
String ajax = request.getParameter("__ajax");
return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml");
}
/**
* 获取客户端 IP 地址
*
* @return 客户端 IP 地址
*/
public static String getClientIP() {
return getClientIP(getRequest());
}
/**
* 对内容进行 URL 编码
*
* @param str 内容
* @return 编码后的内容
*/
public static String urlEncode(String str) {
return URLEncoder.encode(str, StandardCharsets.UTF_8);
}
/**
* 对内容进行 URL 解码
*
* @param str 内容
* @return 解码后的内容
*/
public static String urlDecode(String str) {
return URLDecoder.decode(str, StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,67 @@
package org.dromara.common.core.utils;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
/**
* spring工具类
*
* @author Lion Li
*/
@Component
public final class SpringUtils extends SpringUtil {
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义则返回true
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype
* 如果与给定名字相应的bean定义没有被找到将会抛出一个异常NoSuchBeanDefinitionException
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @return Class 注册对象的类型
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名则返回这些别名
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
/**
* 获取aop代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) {
return (T) getBean(invoker.getClass());
}
/**
* 获取spring上下文
*/
public static ApplicationContext context() {
return getApplicationContext();
}
public static boolean isVirtual() {
return Threading.VIRTUAL.isActive(getBean(Environment.class));
}
}

View File

@ -0,0 +1,283 @@
package org.dromara.common.core.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* stream 流工具类
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class StreamUtils {
/**
* 将collection过滤
*
* @param collection 需要转化的集合
* @param function 过滤方法
* @return 过滤后的list
*/
public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
}
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
return collection.stream().filter(function).collect(Collectors.toList());
}
/**
* 找到流中满足条件的第一个元素
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的第一个元素没有则返回null
*/
public static <E> E findFirst(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return null;
}
return collection.stream().filter(function).findFirst().orElse(null);
}
/**
* 找到流中任意一个满足条件的元素
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的任意一个元素没有则返回null
*/
public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return Optional.empty();
}
return collection.stream().filter(function).findAny();
}
/**
* 将collection拼接
*
* @param collection 需要转化的集合
* @param function 拼接方法
* @return 拼接后的list
*/
public static <E> String join(Collection<E> collection, Function<E, String> function) {
return join(collection, function, StringUtils.SEPARATOR);
}
/**
* 将collection拼接
*
* @param collection 需要转化的集合
* @param function 拼接方法
* @param delimiter 拼接符
* @return 拼接后的list
*/
public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {
if (CollUtil.isEmpty(collection)) {
return StringUtils.EMPTY;
}
return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
}
/**
* 将collection排序
*
* @param collection 需要转化的集合
* @param comparing 排序方法
* @return 排序后的list
*/
public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
}
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
}
/**
* 将collection转化为类型不变的map<br>
* <B>{@code Collection<V> ----> Map<K,V>}</B>
*
* @param collection 需要转化的集合
* @param key V类型转化为K类型的lambda方法
* @param <V> collection中的泛型
* @param <K> map中的key类型
* @return 转化后的map
*/
public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
}
/**
* 将Collection转化为map(value类型与collection的泛型不同)<br>
* <B>{@code Collection<E> -----> Map<K,V> }</B>
*
* @param collection 需要转化的集合
* @param key E类型转化为K类型的lambda方法
* @param value E类型转化为V类型的lambda方法
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @param <V> map中的value类型
* @return 转化后的map
*/
public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
}
/**
* 将collection按照规则(比如有相同的班级id)分类成map<br>
* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
*
* @param collection 需要分类的集合
* @param key 分类的规则
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @return 分类后的map
*/
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection
.stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
}
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B>
*
* @param collection 需要分类的集合
* @param key1 第一个分类的规则
* @param key2 第二个分类的规则
* @param <E> 集合元素类型
* @param <K> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @return 分类后的map
*/
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection
.stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
}
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B>
*
* @param collection 需要分类的集合
* @param key1 第一个分类的规则
* @param key2 第二个分类的规则
* @param <T> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @param <E> collection中的泛型
* @return 分类后的map
*/
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
return MapUtil.newHashMap();
}
return collection
.stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
}
/**
* 将collection转化为List集合但是两者的泛型不同<br>
* <B>{@code Collection<E> ------> List<T> } </B>
*
* @param collection 需要转化的集合
* @param function collection中的泛型转化为list泛型的lambda表达式
* @param <E> collection中的泛型
* @param <T> List中的泛型
* @return 转化后的list
*/
public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
}
return collection
.stream()
.map(function)
.filter(Objects::nonNull)
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
.collect(Collectors.toList());
}
/**
* 将collection转化为Set集合但是两者的泛型不同<br>
* <B>{@code Collection<E> ------> Set<T> } </B>
*
* @param collection 需要转化的集合
* @param function collection中的泛型转化为set泛型的lambda表达式
* @param <E> collection中的泛型
* @param <T> Set中的泛型
* @return 转化后的Set
*/
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
if (CollUtil.isEmpty(collection) || function == null) {
return CollUtil.newHashSet();
}
return collection
.stream()
.map(function)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}
/**
* 合并两个相同key类型的map
*
* @param map1 第一个需要合并的 map
* @param map2 第二个需要合并的 map
* @param merge 合并的lambda将key value1 value2合并成最终的类型,注意value可能为空的情况
* @param <K> map中的key类型
* @param <X> 第一个 map的value类型
* @param <Y> 第二个 map的value类型
* @param <V> 最终map的value类型
* @return 合并后的map
*/
public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
return MapUtil.newHashMap();
} else if (MapUtil.isEmpty(map1)) {
map1 = MapUtil.newHashMap();
} else if (MapUtil.isEmpty(map2)) {
map2 = MapUtil.newHashMap();
}
Set<K> key = new HashSet<>();
key.addAll(map1.keySet());
key.addAll(map2.keySet());
Map<K, V> map = new HashMap<>();
for (K t : key) {
X x = map1.get(t);
Y y = map2.get(t);
V z = merge.apply(x, y);
if (z != null) {
map.put(t, z);
}
}
return map;
}
}

View File

@ -0,0 +1,406 @@
package org.dromara.common.core.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import org.springframework.util.AntPathMatcher;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 字符串工具类
*
* @author Lion Li
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
public static final String SEPARATOR = ",";
public static final String SLASH = "/";
@Deprecated
private StringUtils() {
}
/**
* 获取参数不为空值
*
* @param str defaultValue 要判断的value
* @return value 返回值
*/
public static String blankToDefault(String str, String defaultValue) {
return StrUtil.blankToDefault(str, defaultValue);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true为空 false非空
*/
public static boolean isEmpty(String str) {
return StrUtil.isEmpty(str);
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true非空串 false空串
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* 去空格
*/
public static String trim(String str) {
return StrUtil.trim(str);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
return substring(str, start, str.length());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
return StrUtil.sub(str, start, end);
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* <br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is {} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params) {
return StrUtil.format(template, params);
}
/**
* 是否为http(s)://开头
*
* @param link 链接
* @return 结果
*/
public static boolean ishttp(String link) {
return Validator.isUrl(link);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static Set<String> str2Set(String str, String sep) {
return new HashSet<>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
List<String> list = new ArrayList<>();
if (isEmpty(str)) {
return list;
}
// 过滤空白字符串
if (filterBlank && isBlank(str)) {
return list;
}
String[] split = str.split(sep);
for (String string : split) {
if (filterBlank && isBlank(string)) {
continue;
}
if (trim) {
string = trim(string);
}
list.add(string);
}
return list;
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences);
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str) {
return StrUtil.toUnderlineCase(str);
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs) {
return StrUtil.equalsAnyIgnoreCase(str, strs);
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式如果转换前的下划线大写方式命名的字符串为空则返回空字符串 例如HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
return StrUtil.upperFirst(StrUtil.toCamelCase(name));
}
/**
* 驼峰式命名法 例如user_name->userName
*/
public static String toCamelCase(String s) {
return StrUtil.toCamelCase(s);
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (isEmpty(str) || CollUtil.isEmpty(strs)) {
return false;
}
for (String pattern : strs) {
if (isMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
*/
public static boolean isMatch(String pattern, String url) {
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
/**
* 数字左边补齐0使之达到指定长度注意如果数字转换为字符串后长度大于size则只保留 最后size个字符
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式该字符串为指定长度
*/
public static String padl(final Number num, final int size) {
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐如果原始字符串s长度大于size则只保留最后size个字符
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串由原字符串左补齐或截取得到
*/
public static String padl(final String s, final int size, final char c) {
final StringBuilder sb = new StringBuilder(size);
if (s != null) {
final int len = s.length();
if (s.length() <= size) {
sb.append(String.valueOf(c).repeat(size - len));
sb.append(s);
} else {
return s.substring(len - size, len);
}
} else {
sb.append(String.valueOf(c).repeat(Math.max(0, size)));
}
return sb.toString();
}
/**
* 切分字符串(分隔符默认逗号)
*
* @param str 被切分的字符串
* @return 分割后的数据列表
*/
public static List<String> splitList(String str) {
return splitTo(str, Convert::toStr);
}
/**
* 切分字符串
*
* @param str 被切分的字符串
* @param separator 分隔符
* @return 分割后的数据列表
*/
public static List<String> splitList(String str, String separator) {
return splitTo(str, separator, Convert::toStr);
}
/**
* 切分字符串自定义转换(分隔符默认逗号)
*
* @param str 被切分的字符串
* @param mapper 自定义转换
* @return 分割后的数据列表
*/
public static <T> List<T> splitTo(String str, Function<? super Object, T> mapper) {
return splitTo(str, SEPARATOR, mapper);
}
/**
* 切分字符串自定义转换
*
* @param str 被切分的字符串
* @param separator 分隔符
* @param mapper 自定义转换
* @return 分割后的数据列表
*/
public static <T> List<T> splitTo(String str, String separator, Function<? super Object, T> mapper) {
if (isBlank(str)) {
return new ArrayList<>(0);
}
return StrUtil.split(str, separator)
.stream()
.filter(Objects::nonNull)
.map(mapper)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
/**
* 不区分大小写检查 CharSequence 是否以指定的前缀开头
*
* @param str 要检查的 CharSequence 可能为 null
* @param prefixs 要查找的前缀可能为 null
* @return 是否包含
*/
public static boolean startWithAnyIgnoreCase(CharSequence str, CharSequence... prefixs) {
// 判断是否是以指定字符串开头
for (CharSequence prefix : prefixs) {
if (StringUtils.startsWithIgnoreCase(str, prefix)) {
return true;
}
}
return false;
}
public static String getFirstCharToUpper(String input) {
if (input == null || input.isEmpty()) {
return ""; // 如果字符串为空或长度为0返回空字符串
}
// 获取第一个字符并转为大写
return String.valueOf(input.charAt(0)).toUpperCase();
}
/**
* 裁剪字符串保留指定长度的字符中文占2个字符其他占1个字符
*
* @param input 输入字符串
* @param maxLength 最大字符长度
* @return 裁剪后的字符串
*/
public static String truncateString(String input, int maxLength) {
if (input == null || maxLength <= 0) {
return "";
}
int length = 0;
StringBuilder result = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
// 判断是否为中文字符
if (isChinese(c)) {
length += 2;
} else {
length += 1;
}
// 如果超过最大长度则停止
if (length > maxLength) {
break;
}
result.append(c);
}
return result.toString();
}
/**
* 判断字符是否为中文字符
*
* @param c 字符
* @return 是否为中文字符
*/
public static boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,96 @@
package org.dromara.common.core.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.lang.tree.parser.NodeParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 扩展 hutool TreeUtil 封装系统树构建
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TreeBuildUtils extends TreeUtil {
/**
* 根据前端定制差异化字段
*/
public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label");
/**
* 构建树形结构
*
* @param <T> 输入节点的类型
* @param <K> 节点ID的类型
* @param list 节点列表其中包含了要构建树形结构的所有节点
* @param nodeParser 解析器用于将输入节点转换为树节点
* @return 构建好的树形结构列表
*/
public static <T, K> List<Tree<K>> build(List<T> list, NodeParser<T, K> nodeParser) {
if (CollUtil.isEmpty(list)) {
return CollUtil.newArrayList();
}
K k = ReflectUtils.invokeGetter(list.get(0), "parentId");
return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser);
}
/**
* 构建树形结构
*
* @param <T> 输入节点的类型
* @param <K> 节点ID的类型
* @param parentId 顶级节点
* @param list 节点列表其中包含了要构建树形结构的所有节点
* @param nodeParser 解析器用于将输入节点转换为树节点
* @return 构建好的树形结构列表
*/
public static <T, K> List<Tree<K>> build(List<T> list, K parentId, NodeParser<T, K> nodeParser) {
if (CollUtil.isEmpty(list)) {
return CollUtil.newArrayList();
}
return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser);
}
/**
* 获取节点列表中所有节点的叶子节点
*
* @param <K> 节点ID的类型
* @param nodes 节点列表
* @return 包含所有叶子节点的列表
*/
public static <K> List<Tree<K>> getLeafNodes(List<Tree<K>> nodes) {
if (CollUtil.isEmpty(nodes)) {
return CollUtil.newArrayList();
}
return nodes.stream()
.flatMap(TreeBuildUtils::extractLeafNodes)
.collect(Collectors.toList());
}
/**
* 获取指定节点下的所有叶子节点
*
* @param <K> 节点ID的类型
* @param node 要查找叶子节点的根节点
* @return 包含所有叶子节点的列表
*/
private static <K> Stream<Tree<K>> extractLeafNodes(Tree<K> node) {
if (!node.hasChild()) {
return Stream.of(node);
} else {
// 递归调用获取所有子节点的叶子节点
return node.getChildren().stream()
.flatMap(TreeBuildUtils::extractLeafNodes);
}
}
}

View File

@ -0,0 +1,35 @@
package org.dromara.common.core.utils;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.Set;
/**
* Validator 校验框架工具
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidatorUtils {
private static final Validator VALID = SpringUtils.getBean(Validator.class);
/**
* 对给定对象进行参数校验并根据指定的校验组进行校验
*
* @param object 要进行校验的对象
* @param groups 校验组
* @throws ConstraintViolationException 如果校验不通过则抛出参数校验异常
*/
public static <T> void validate(T object, Class<?>... groups) {
Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
if (!validate.isEmpty()) {
throw new ConstraintViolationException("参数校验异常", validate);
}
}
}

View File

@ -0,0 +1,40 @@
package org.dromara.common.core.utils.file;
/**
* 媒体类型工具类
*
* @author ruoyi
*/
public class MimeTypeUtils {
public static final String IMAGE_PNG = "image/png";
public static final String IMAGE_JPG = "image/jpg";
public static final String IMAGE_JPEG = "image/jpeg";
public static final String IMAGE_BMP = "image/bmp";
public static final String IMAGE_GIF = "image/gif";
public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
public static final String[] FLASH_EXTENSION = {"swf", "flv"};
public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
"asf", "rm", "rmvb"};
public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf
"pdf"};
}

View File

@ -0,0 +1,33 @@
package org.dromara.common.core.utils.ip;
import cn.hutool.core.net.NetUtil;
import cn.hutool.http.HtmlUtil;
import org.dromara.common.core.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 获取地址类
*
* @author Lion Li
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class AddressUtils {
// 未知地址
public static final String UNKNOWN = "XX XX";
public static String getRealAddressByIP(String ip) {
if (StringUtils.isBlank(ip)) {
return UNKNOWN;
}
// 内网不查询
ip = StringUtils.contains(ip, "0:0:0:0:0:0:0:1") ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
if (NetUtil.isInnerIP(ip)) {
return "内网IP";
}
return RegionUtils.getCityInfo(ip);
}
}

View File

@ -0,0 +1,31 @@
package org.dromara.common.core.utils.regex;
import cn.hutool.core.util.ReUtil;
import org.dromara.common.core.constant.RegexConstants;
/**
* 正则相关工具类
*
* @author Feng
*/
public final class RegexUtils extends ReUtil {
/**
* 从输入字符串中提取匹配的部分如果没有匹配则返回默认值
*
* @param input 要提取的输入字符串
* @param regex 用于匹配的正则表达式可以使用 {@link RegexConstants} 中定义的常量
* @param defaultInput 如果没有匹配时返回的默认值
* @return 如果找到匹配的部分则返回匹配的部分否则返回默认值
*/
public static String extractFromString(String input, String regex, String defaultInput) {
try {
String str = ReUtil.get(regex, input, 1);
return str == null ? defaultInput : str;
} catch (Exception e) {
return defaultInput;
}
}
}

View File

@ -0,0 +1,105 @@
package org.dromara.common.core.utils.regex;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.lang.Validator;
import org.dromara.common.core.factory.RegexPatternPoolFactory;
import java.util.regex.Pattern;
/**
* 正则字段校验器
* 主要验证字段非空是否为满足指定格式等
*
* @author Feng
*/
public class RegexValidator extends Validator {
/**
* 字典类型必须以字母开头且只能为小写字母数字下滑线
*/
public static final Pattern DICTIONARY_TYPE = RegexPatternPoolFactory.DICTIONARY_TYPE;
/**
* 身份证号码后6位
*/
public static final Pattern ID_CARD_LAST_6 = RegexPatternPoolFactory.ID_CARD_LAST_6;
/**
* QQ号码
*/
public static final Pattern QQ_NUMBER = RegexPatternPoolFactory.QQ_NUMBER;
/**
* 邮政编码
*/
public static final Pattern POSTAL_CODE = RegexPatternPoolFactory.POSTAL_CODE;
/**
* 注册账号
*/
public static final Pattern ACCOUNT = RegexPatternPoolFactory.ACCOUNT;
/**
* 密码包含至少8个字符包括大写字母小写字母数字和特殊字符
*/
public static final Pattern PASSWORD = RegexPatternPoolFactory.PASSWORD;
/**
* 通用状态0表示正常1表示停用
*/
public static final Pattern STATUS = RegexPatternPoolFactory.STATUS;
/**
* 检查输入的账号是否匹配预定义的规则
*
* @param value 要验证的账号
* @return 如果账号符合规则返回 true否则返回 false
*/
public static boolean isAccount(CharSequence value) {
return isMatchRegex(ACCOUNT, value);
}
/**
* 验证输入的账号是否符合规则如果不符合则抛出 ValidateException 异常
*
* @param value 要验证的账号
* @param errorMsg 验证失败时抛出的异常消息
* @param <T> CharSequence 的子类型
* @return 如果验证通过返回输入的账号
* @throws ValidateException 如果验证失败
*/
public static <T extends CharSequence> T validateAccount(T value, String errorMsg) throws ValidateException {
if (!isAccount(value)) {
throw new ValidateException(errorMsg);
}
return value;
}
/**
* 检查输入的状态是否匹配预定义的规则
*
* @param value 要验证的状态
* @return 如果状态符合规则返回 true否则返回 false
*/
public static boolean isStatus(CharSequence value) {
return isMatchRegex(STATUS, value);
}
/**
* 验证输入的状态是否符合规则如果不符合则抛出 ValidateException 异常
*
* @param value 要验证的状态
* @param errorMsg 验证失败时抛出的异常消息
* @param <T> CharSequence 的子类型
* @return 如果验证通过返回输入的状态
* @throws ValidateException 如果验证失败
*/
public static <T extends CharSequence> T validateStatus(T value, String errorMsg) throws ValidateException {
if (!isStatus(value)) {
throw new ValidateException(errorMsg);
}
return value;
}
}

View File

@ -0,0 +1,9 @@
package org.dromara.common.core.validate;
/**
* 校验分组 edit
*
* @author Lion Li
*/
public interface EditGroup {
}

View File

@ -0,0 +1,9 @@
package org.dromara.common.core.validate;
/**
* 校验分组 query
*
* @author Lion Li
*/
public interface QueryGroup {
}

View File

@ -0,0 +1,37 @@
package org.dromara.common.core.validate.enumd;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.reflect.ReflectUtils;
/**
* 自定义枚举校验注解实现
*
* @author 秋辞未寒
* @date 2024-12-09
*/
public class EnumPatternValidator implements ConstraintValidator<EnumPattern, String> {
private EnumPattern annotation;;
@Override
public void initialize(EnumPattern annotation) {
ConstraintValidator.super.initialize(annotation);
this.annotation = annotation;
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if (StringUtils.isNotBlank(value)) {
String fieldName = annotation.fieldName();
for (Object e : annotation.type().getEnumConstants()) {
if (value.equals(ReflectUtils.invokeGetter(e, fieldName))) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,21 @@
package org.dromara.common.core.xss;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HtmlUtil;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* 自定义xss校验注解实现
*
* @author Lion Li
*/
public class XssValidator implements ConstraintValidator<Xss, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value);
}
}

View File

@ -0,0 +1,6 @@
org.dromara.common.core.config.ApplicationConfig
org.dromara.common.core.config.AsyncConfig
org.dromara.common.core.config.RuoYiConfig
org.dromara.common.core.config.ThreadPoolConfig
org.dromara.common.core.config.ValidatorConfig
org.dromara.common.core.utils.SpringUtils

View File

@ -0,0 +1,126 @@
package org.dromara.common.doc.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.doc.config.properties.SpringDocProperties;
import org.dromara.common.doc.handler.OpenApiHandler;
import org.springdoc.core.configuration.SpringDocConfiguration;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.providers.JavadocProvider;
import org.springdoc.core.service.OpenAPIService;
import org.springdoc.core.service.SecurityService;
import org.springdoc.core.utils.PropertyResolverUtils;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* Swagger 文档配置
*
* @author Lion Li
*/
@RequiredArgsConstructor
@AutoConfiguration(before = SpringDocConfiguration.class)
@EnableConfigurationProperties(SpringDocProperties.class)
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
public class SpringDocConfig {
private final ServerProperties serverProperties;
@Bean
@ConditionalOnMissingBean(OpenAPI.class)
public OpenAPI openApi(SpringDocProperties properties) {
OpenAPI openApi = new OpenAPI();
// 文档基本信息
SpringDocProperties.InfoProperties infoProperties = properties.getInfo();
Info info = convertInfo(infoProperties);
openApi.info(info);
// 扩展文档信息
openApi.externalDocs(properties.getExternalDocs());
openApi.tags(properties.getTags());
openApi.paths(properties.getPaths());
openApi.components(properties.getComponents());
Set<String> keySet = properties.getComponents().getSecuritySchemes().keySet();
List<SecurityRequirement> list = new ArrayList<>();
SecurityRequirement securityRequirement = new SecurityRequirement();
keySet.forEach(securityRequirement::addList);
list.add(securityRequirement);
openApi.security(list);
return openApi;
}
private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
Info info = new Info();
info.setTitle(infoProperties.getTitle());
info.setDescription(infoProperties.getDescription());
info.setContact(infoProperties.getContact());
info.setLicense(infoProperties.getLicense());
info.setVersion(infoProperties.getVersion());
return info;
}
/**
* 自定义 openapi 处理器
*/
@Bean
public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI,
SecurityService securityParser,
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider) {
return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider);
}
/**
* 对已经生成好的 OpenApi 进行自定义操作
*/
@Bean
public OpenApiCustomizer openApiCustomizer() {
String contextPath = serverProperties.getServlet().getContextPath();
String finalContextPath;
if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) {
finalContextPath = "";
} else {
finalContextPath = contextPath;
}
// 对所有路径增加前置上下文路径
return openApi -> {
Paths oldPaths = openApi.getPaths();
if (oldPaths instanceof PlusPaths) {
return;
}
PlusPaths newPaths = new PlusPaths();
oldPaths.forEach((k, v) -> newPaths.addPathItem(finalContextPath + k, v));
openApi.setPaths(newPaths);
};
}
/**
* 单独使用一个类便于判断 解决springdoc路径拼接重复问题
*
* @author Lion Li
*/
static class PlusPaths extends Paths {
public PlusPaths() {
super();
}
}
}

View File

@ -0,0 +1,94 @@
package org.dromara.common.doc.config.properties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.tags.Tag;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import java.util.List;
/**
* swagger 配置属性
*
* @author Lion Li
*/
@Data
@ConfigurationProperties(prefix = "springdoc")
public class SpringDocProperties {
/**
* 文档基本信息
*/
@NestedConfigurationProperty
private InfoProperties info = new InfoProperties();
/**
* 扩展文档地址
*/
@NestedConfigurationProperty
private ExternalDocumentation externalDocs;
/**
* 标签
*/
private List<Tag> tags = null;
/**
* 路径
*/
@NestedConfigurationProperty
private Paths paths = null;
/**
* 组件
*/
@NestedConfigurationProperty
private Components components = null;
/**
* <p>
* 文档的基础属性信息
* </p>
*
* @see io.swagger.v3.oas.models.info.Info
*
* 为了 springboot 自动生产配置提示信息所以这里复制一个类出来
*/
@Data
public static class InfoProperties {
/**
* 标题
*/
private String title = null;
/**
* 描述
*/
private String description = null;
/**
* 联系人信息
*/
@NestedConfigurationProperty
private Contact contact = null;
/**
* 许可证
*/
@NestedConfigurationProperty
private License license = null;
/**
* 版本
*/
private String version = null;
}
}

View File

@ -0,0 +1,253 @@
package org.dromara.common.doc.handler;
import cn.hutool.core.io.IoUtil;
import io.swagger.v3.core.jackson.TypeNameResolver;
import io.swagger.v3.core.util.AnnotationsUtils;
import io.swagger.v3.oas.annotations.tags.Tags;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.providers.JavadocProvider;
import org.springdoc.core.service.OpenAPIService;
import org.springdoc.core.service.SecurityService;
import org.springdoc.core.utils.PropertyResolverUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.method.HandlerMethod;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 自定义 openapi 处理器
* 对源码功能进行修改 增强使用
*/
@Slf4j
@SuppressWarnings("all")
public class OpenApiHandler extends OpenAPIService {
/**
* The Basic error controller.
*/
private static Class<?> basicErrorController;
/**
* The Security parser.
*/
private final SecurityService securityParser;
/**
* The Mappings map.
*/
private final Map<String, Object> mappingsMap = new HashMap<>();
/**
* The Springdoc tags.
*/
private final Map<HandlerMethod, Tag> springdocTags = new HashMap<>();
/**
* The Open api builder customisers.
*/
private final Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers;
/**
* The server base URL customisers.
*/
private final Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers;
/**
* The Spring doc config properties.
*/
private final SpringDocConfigProperties springDocConfigProperties;
/**
* The Cached open api map.
*/
private final Map<String, OpenAPI> cachedOpenAPI = new HashMap<>();
/**
* The Property resolver utils.
*/
private final PropertyResolverUtils propertyResolverUtils;
/**
* The javadoc provider.
*/
private final Optional<JavadocProvider> javadocProvider;
/**
* The Context.
*/
private ApplicationContext context;
/**
* The Open api.
*/
private OpenAPI openAPI;
/**
* The Is servers present.
*/
private boolean isServersPresent;
/**
* The Server base url.
*/
private String serverBaseUrl;
/**
* Instantiates a new Open api builder.
*
* @param openAPI the open api
* @param securityParser the security parser
* @param springDocConfigProperties the spring doc config properties
* @param propertyResolverUtils the property resolver utils
* @param openApiBuilderCustomizers the open api builder customisers
* @param serverBaseUrlCustomizers the server base url customizers
* @param javadocProvider the javadoc provider
*/
public OpenApiHandler(Optional<OpenAPI> openAPI, SecurityService securityParser,
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers,
Optional<JavadocProvider> javadocProvider) {
super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider);
if (openAPI.isPresent()) {
this.openAPI = openAPI.get();
if (this.openAPI.getComponents() == null)
this.openAPI.setComponents(new Components());
if (this.openAPI.getPaths() == null)
this.openAPI.setPaths(new Paths());
if (!CollectionUtils.isEmpty(this.openAPI.getServers()))
this.isServersPresent = true;
}
this.propertyResolverUtils = propertyResolverUtils;
this.securityParser = securityParser;
this.springDocConfigProperties = springDocConfigProperties;
this.openApiBuilderCustomisers = openApiBuilderCustomizers;
this.serverBaseUrlCustomizers = serverBaseUrlCustomizers;
this.javadocProvider = javadocProvider;
if (springDocConfigProperties.isUseFqn())
TypeNameResolver.std.setUseFqn(true);
}
@Override
public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) {
Set<Tag> tags = new HashSet<>();
Set<String> tagsStr = new HashSet<>();
buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale);
buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale);
if (!CollectionUtils.isEmpty(tagsStr))
tagsStr = tagsStr.stream()
.map(str -> propertyResolverUtils.resolve(str, locale))
.collect(Collectors.toSet());
if (springdocTags.containsKey(handlerMethod)) {
io.swagger.v3.oas.models.tags.Tag tag = springdocTags.get(handlerMethod);
tagsStr.add(tag.getName());
if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) {
openAPI.addTagsItem(tag);
}
}
if (!CollectionUtils.isEmpty(tagsStr)) {
if (CollectionUtils.isEmpty(operation.getTags()))
operation.setTags(new ArrayList<>(tagsStr));
else {
Set<String> operationTagsSet = new HashSet<>(operation.getTags());
operationTagsSet.addAll(tagsStr);
operation.getTags().clear();
operation.getTags().addAll(operationTagsSet);
}
}
if (isAutoTagClasses(operation)) {
if (javadocProvider.isPresent()) {
String description = javadocProvider.get().getClassJavadoc(handlerMethod.getBeanType());
if (StringUtils.isNotBlank(description)) {
io.swagger.v3.oas.models.tags.Tag tag = new io.swagger.v3.oas.models.tags.Tag();
// 自定义部分 修改使用java注释当tag名
List<String> list = IoUtil.readLines(new StringReader(description), new ArrayList<>());
// tag.setName(tagAutoName);
tag.setName(list.get(0));
operation.addTagsItem(list.get(0));
tag.setDescription(description);
if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) {
openAPI.addTagsItem(tag);
}
}
} else {
String tagAutoName = splitCamelCase(handlerMethod.getBeanType().getSimpleName());
operation.addTagsItem(tagAutoName);
}
}
if (!CollectionUtils.isEmpty(tags)) {
// Existing tags
List<io.swagger.v3.oas.models.tags.Tag> openApiTags = openAPI.getTags();
if (!CollectionUtils.isEmpty(openApiTags))
tags.addAll(openApiTags);
openAPI.setTags(new ArrayList<>(tags));
}
// Handle SecurityRequirement at operation level
io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser
.getSecurityRequirements(handlerMethod);
if (securityRequirements != null) {
if (securityRequirements.length == 0)
operation.setSecurity(Collections.emptyList());
else
securityParser.buildSecurityRequirement(securityRequirements, operation);
}
return operation;
}
private void buildTagsFromMethod(Method method, Set<io.swagger.v3.oas.models.tags.Tag> tags, Set<String> tagsStr, Locale locale) {
// method tags
Set<Tags> tagsSet = AnnotatedElementUtils
.findAllMergedAnnotations(method, Tags.class);
Set<io.swagger.v3.oas.annotations.tags.Tag> methodTags = tagsSet.stream()
.flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet());
methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class));
if (!CollectionUtils.isEmpty(methodTags)) {
tagsStr.addAll(StreamUtils.toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale)));
List<io.swagger.v3.oas.annotations.tags.Tag> allTags = new ArrayList<>(methodTags);
addTags(allTags, tags, locale);
}
}
private void addTags(List<io.swagger.v3.oas.annotations.tags.Tag> sourceTags, Set<io.swagger.v3.oas.models.tags.Tag> tags, Locale locale) {
Optional<Set<io.swagger.v3.oas.models.tags.Tag>> optionalTagSet = AnnotationsUtils
.getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true);
optionalTagSet.ifPresent(tagsSet -> {
tagsSet.forEach(tag -> {
tag.name(propertyResolverUtils.resolve(tag.getName(), locale));
tag.description(propertyResolverUtils.resolve(tag.getDescription(), locale));
if (tags.stream().noneMatch(t -> t.getName().equals(tag.getName())))
tags.add(tag);
});
});
}
}

View File

@ -0,0 +1 @@
org.dromara.common.doc.config.SpringDocConfig

View File

@ -0,0 +1,20 @@
package org.dromara.common.encrypt.annotation;
import java.lang.annotation.*;
/**
* 强制加密注解
*
* @author Michelle.Chung
*/
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiEncrypt {
/**
* 响应加密忽略默认不加密 true 时加密
*/
boolean response() default false;
}

Some files were not shown because too many files have changed in this diff Show More