diff --git a/cutejava-springboot3/.gitignore b/cutejava-springboot3/.gitignore
new file mode 100644
index 00000000..a4dad206
--- /dev/null
+++ b/cutejava-springboot3/.gitignore
@@ -0,0 +1,9 @@
+### IDEA ###
+.DS_Store
+~/*
+.idea/*
+*.iml
+*/target/*
+*/*.iml
+/.gradle/
+/application.pid
\ No newline at end of file
diff --git a/cutejava-springboot3/LICENSE b/cutejava-springboot3/LICENSE
new file mode 100644
index 00000000..78a36cb2
--- /dev/null
+++ b/cutejava-springboot3/LICENSE
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "{}" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright 2019 Zheng Jie
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/cutejava-springboot3/cutejava-framework/pom.xml b/cutejava-springboot3/cutejava-framework/pom.xml
new file mode 100644
index 00000000..cfdb3b22
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/pom.xml
@@ -0,0 +1,12 @@
+
+
+
+ cutejava
+ cn.odboy
+ 1.4.1
+
+ 4.0.0
+ cutejava-framework
+ 公共模块
+
\ No newline at end of file
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousAccess.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousAccess.java
new file mode 100644
index 00000000..a941eac2
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousAccess.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.odboy.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 用于标记匿名访问方法
+ */
+@Inherited
+@Documented
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnonymousAccess {
+
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousDeleteMapping.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousDeleteMapping.java
new file mode 100644
index 00000000..f37cb132
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousDeleteMapping.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.annotation;
+
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for mapping HTTP {@code DELETE} requests onto specific handler methods. 支持匿名访问 DeleteMapping
+ *
+ * @see AnonymousGetMapping
+ * @see AnonymousPostMapping
+ * @see AnonymousPutMapping
+ * @see AnonymousPatchMapping
+ * @see RequestMapping
+ */
+@AnonymousAccess
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@RequestMapping(method = RequestMethod.DELETE)
+public @interface AnonymousDeleteMapping {
+
+ /**
+ * Alias for {@link RequestMapping#name}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String name() default "";
+
+ /**
+ * Alias for {@link RequestMapping#value}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] value() default {};
+
+ /**
+ * Alias for {@link RequestMapping#path}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] path() default {};
+
+ /**
+ * Alias for {@link RequestMapping#params}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] params() default {};
+
+ /**
+ * Alias for {@link RequestMapping#headers}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] headers() default {};
+
+ /**
+ * Alias for {@link RequestMapping#consumes}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
+
+ /**
+ * Alias for {@link RequestMapping#produces}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] produces() default {};
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousGetMapping.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousGetMapping.java
new file mode 100644
index 00000000..e72c492b
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousGetMapping.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.annotation;
+
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for mapping HTTP {@code GET} requests onto specific handler methods.
+ *
+ * 支持匿名访问 GetMapping
+ *
+ * @see RequestMapping
+ */
+@AnonymousAccess
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@RequestMapping(method = RequestMethod.GET)
+public @interface AnonymousGetMapping {
+
+ /**
+ * Alias for {@link RequestMapping#name}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String name() default "";
+
+ /**
+ * Alias for {@link RequestMapping#value}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] value() default {};
+
+ /**
+ * Alias for {@link RequestMapping#path}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] path() default {};
+
+ /**
+ * Alias for {@link RequestMapping#params}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] params() default {};
+
+ /**
+ * Alias for {@link RequestMapping#headers}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] headers() default {};
+
+ /**
+ * Alias for {@link RequestMapping#consumes}.
+ *
+ * @since 4.3.5
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
+
+ /**
+ * Alias for {@link RequestMapping#produces}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] produces() default {};
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPatchMapping.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPatchMapping.java
new file mode 100644
index 00000000..4a49586e
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPatchMapping.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.annotation;
+
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for mapping HTTP {@code PATCH} requests onto specific handler methods. 支持匿名访问 PatchMapping
+ *
+ * @see AnonymousGetMapping
+ * @see AnonymousPostMapping
+ * @see AnonymousPutMapping
+ * @see AnonymousDeleteMapping
+ * @see RequestMapping
+ */
+@AnonymousAccess
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@RequestMapping(method = RequestMethod.PATCH)
+public @interface AnonymousPatchMapping {
+
+ /**
+ * Alias for {@link RequestMapping#name}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String name() default "";
+
+ /**
+ * Alias for {@link RequestMapping#value}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] value() default {};
+
+ /**
+ * Alias for {@link RequestMapping#path}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] path() default {};
+
+ /**
+ * Alias for {@link RequestMapping#params}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] params() default {};
+
+ /**
+ * Alias for {@link RequestMapping#headers}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] headers() default {};
+
+ /**
+ * Alias for {@link RequestMapping#consumes}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
+
+ /**
+ * Alias for {@link RequestMapping#produces}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] produces() default {};
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPostMapping.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPostMapping.java
new file mode 100644
index 00000000..aeaa028f
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPostMapping.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.annotation;
+
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for mapping HTTP {@code POST} requests onto specific handler methods. 支持匿名访问 PostMapping
+ *
+ * @see AnonymousGetMapping
+ * @see AnonymousPostMapping
+ * @see AnonymousPutMapping
+ * @see AnonymousDeleteMapping
+ * @see RequestMapping
+ */
+@AnonymousAccess
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@RequestMapping(method = RequestMethod.POST)
+public @interface AnonymousPostMapping {
+
+ /**
+ * Alias for {@link RequestMapping#name}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String name() default "";
+
+ /**
+ * Alias for {@link RequestMapping#value}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] value() default {};
+
+ /**
+ * Alias for {@link RequestMapping#path}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] path() default {};
+
+ /**
+ * Alias for {@link RequestMapping#params}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] params() default {};
+
+ /**
+ * Alias for {@link RequestMapping#headers}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] headers() default {};
+
+ /**
+ * Alias for {@link RequestMapping#consumes}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
+
+ /**
+ * Alias for {@link RequestMapping#produces}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] produces() default {};
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPutMapping.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPutMapping.java
new file mode 100644
index 00000000..5f54ef12
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/annotation/AnonymousPutMapping.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.annotation;
+
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation for mapping HTTP {@code PUT} requests onto specific handler methods. 支持匿名访问 PutMapping
+ *
+ * @see AnonymousGetMapping
+ * @see AnonymousPostMapping
+ * @see AnonymousPutMapping
+ * @see AnonymousDeleteMapping
+ * @see RequestMapping
+ */
+@AnonymousAccess
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@RequestMapping(method = RequestMethod.PUT)
+public @interface AnonymousPutMapping {
+
+ /**
+ * Alias for {@link RequestMapping#name}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String name() default "";
+
+ /**
+ * Alias for {@link RequestMapping#value}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] value() default {};
+
+ /**
+ * Alias for {@link RequestMapping#path}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] path() default {};
+
+ /**
+ * Alias for {@link RequestMapping#params}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] params() default {};
+
+ /**
+ * Alias for {@link RequestMapping#headers}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] headers() default {};
+
+ /**
+ * Alias for {@link RequestMapping#consumes}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
+
+ /**
+ * Alias for {@link RequestMapping#produces}.
+ */
+ @AliasFor(annotation = RequestMapping.class) String[] produces() default {};
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsArgs.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsArgs.java
new file mode 100644
index 00000000..1ab9f522
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsArgs.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 通用参数
+ *
+ * @author odboy
+ * @date 2025-07-23
+ */
+public class CsArgs {
+ @Getter
+ @Setter
+ public static class FindByLongId extends CsObject {
+ @NotNull(message = "id必填")
+ private Long id;
+ }
+
+ @Getter
+ @Setter
+ public static class DeleteById extends CsObject {
+ @NotNull(message = "id必填")
+ private Long id;
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseCreateTimeTb.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseCreateTimeTb.java
new file mode 100644
index 00000000..03c6fc13
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseCreateTimeTb.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+public class CsBaseCreateTimeTb extends CsObject {
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
+ private Date createTime;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseTimeTb.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseTimeTb.java
new file mode 100644
index 00000000..7412d7bc
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseTimeTb.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+public class CsBaseTimeTb extends CsObject {
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
+ private Date createTime;
+
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
+ private Date updateTime;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUpdateTimeTb.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUpdateTimeTb.java
new file mode 100644
index 00000000..4ed12ff3
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUpdateTimeTb.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+public class CsBaseUpdateTimeTb extends CsObject {
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
+ private Date updateTime;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserCreateTimeTb.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserCreateTimeTb.java
new file mode 100644
index 00000000..31da284f
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserCreateTimeTb.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.springframework.data.annotation.CreatedBy;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+public class CsBaseUserCreateTimeTb extends CsObject {
+
+ @CreatedBy
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建人", hidden = true)
+ private String createBy;
+
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
+ private Date createTime;
+
+ /* 分组校验 */
+ public @interface Create {
+ }
+
+ /* 分组校验 */
+ public @interface Update {
+ }
+
+ @Override
+ public String toString() {
+ ToStringBuilder builder = new ToStringBuilder(this);
+ Field[] fields = this.getClass().getDeclaredFields();
+ try {
+ for (Field f : fields) {
+ f.setAccessible(true);
+ builder.append(f.getName(), f.get(this)).append("\n");
+ }
+ } catch (Exception e) {
+ builder.append("toString builder encounter an error");
+ }
+ return builder.toString();
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserTimeLogicTb.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserTimeLogicTb.java
new file mode 100644
index 00000000..4654092e
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserTimeLogicTb.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.LastModifiedBy;
+
+import java.util.Date;
+
+/**
+ * 逻辑删除通用模型
+ *
+ * @author odboy
+ * @date 2025-01-12
+ */
+@Getter
+@Setter
+public class CsBaseUserTimeLogicTb extends CsObject {
+ @CreatedBy
+ @TableField(value = "create_by", fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建人", hidden = true)
+ private String createBy;
+ @LastModifiedBy
+ @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
+ @ApiModelProperty(value = "更新人", hidden = true)
+ private String updateBy;
+ @TableField(value = "create_time", fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建时间", hidden = true)
+ private Date createTime;
+ @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
+ @ApiModelProperty(value = "更新时间", hidden = true)
+ private Date updateTime;
+ @ApiModelProperty(value = "数据有效性", hidden = true)
+ @TableLogic
+ @TableField("available")
+ private Integer available;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserTimeTb.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserTimeTb.java
new file mode 100644
index 00000000..0d15c48d
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsBaseUserTimeTb.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.LastModifiedBy;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+public class CsBaseUserTimeTb extends CsObject {
+
+ @CreatedBy
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建人", hidden = true)
+ private String createBy;
+
+ @LastModifiedBy
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @ApiModelProperty(value = "更新人", hidden = true)
+ private String updateBy;
+
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
+ private Date createTime;
+
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ @ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
+ private Date updateTime;
+
+ /* 分组校验 */
+ public @interface Create {
+ }
+
+ /* 分组校验 */
+ public @interface Update {
+ }
+
+ @Override
+ public String toString() {
+ ToStringBuilder builder = new ToStringBuilder(this);
+ Field[] fields = this.getClass().getDeclaredFields();
+ try {
+ for (Field f : fields) {
+ f.setAccessible(true);
+ builder.append(f.getName(), f.get(this)).append("\n");
+ }
+ } catch (Exception e) {
+ builder.append("toString builder encounter an error");
+ }
+ return builder.toString();
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsObject.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsObject.java
new file mode 100644
index 00000000..1854f4f5
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsObject.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import java.io.Serializable;
+
+/**
+ * 基础对象
+ *
+ * @author odboy
+ * @date 2022-01-12
+ */
+public class CsObject implements Serializable {
+ private static final long serialVersionUID = 1L;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsPageArgs.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsPageArgs.java
new file mode 100644
index 00000000..b209e552
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsPageArgs.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 数据分页参数
+ *
+ * @author odboy
+ * @date 2025-01-20
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CsPageArgs implements Serializable {
+ @NotNull(message = "参数page不能为空")
+ @Min(value = 1, message = "参数page最小值为1")
+ @ApiModelProperty(value = "页码", example = "1")
+ private Integer page;
+ @NotNull(message = "参数size不能为空")
+ @Min(value = 1, message = "参数size最小值为1")
+ @ApiModelProperty(value = "每页数据量", example = "10")
+ private Integer size;
+ private T args;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsPageResult.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsPageResult.java
new file mode 100644
index 00000000..7290b44b
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsPageResult.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 结果封装类
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class CsPageResult extends CsObject {
+ private List content;
+ private long totalElements;
+
+ public static CsPageResult emptyListData() {
+ CsPageResult result = new CsPageResult<>();
+ result.setTotalElements(0);
+ result.setContent(new ArrayList<>());
+ return result;
+ }
+
+ public static CsPageResult listData(IPage page) {
+ CsPageResult result = new CsPageResult<>();
+ result.setTotalElements(page.getTotal());
+ result.setContent(page.getRecords());
+ return result;
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsSelectOptionVo.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsSelectOptionVo.java
new file mode 100644
index 00000000..92d168e2
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/base/CsSelectOptionVo.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.base;
+
+import lombok.*;
+
+import java.util.Map;
+
+/**
+ * 元数据选项
+ *
+ * @author odboy
+ * @date 2025-01-13
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class CsSelectOptionVo extends CsObject {
+ private String label;
+ private String value;
+ private Map ext;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/CaptchaCodeEnum.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/CaptchaCodeEnum.java
new file mode 100644
index 00000000..9077be53
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/CaptchaCodeEnum.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.constant;
+
+/**
+ * 验证码配置枚举
+ */
+public enum CaptchaCodeEnum {
+ /**
+ * 算数
+ */
+ ARITHMETIC,
+ /**
+ * 中文
+ */
+ CHINESE,
+ /**
+ * 中文闪图
+ */
+ CHINESE_GIF,
+ /**
+ * 闪图
+ */
+ GIF,
+ /**
+ * 静态
+ */
+ SPEC
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/FileTypeEnum.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/FileTypeEnum.java
new file mode 100644
index 00000000..9f83eb5c
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/FileTypeEnum.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum FileTypeEnum {
+ /* 文件类型 */
+ IMAGE("image", "图片"),
+ DOC("doc", "文档"),
+ VOICE("voice", "音频"),
+ VIDEO("video", "视频"),
+ OTHER("other", "其他");
+
+ private final String code;
+ private final String description;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/RequestMethodEnum.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/RequestMethodEnum.java
new file mode 100644
index 00000000..87672598
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/RequestMethodEnum.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum RequestMethodEnum {
+
+ /**
+ * 搜寻 @AnonymousGetMapping
+ */
+ GET("GET"),
+
+ /**
+ * 搜寻 @AnonymousPostMapping
+ */
+ POST("POST"),
+
+ /**
+ * 搜寻 @AnonymousPutMapping
+ */
+ PUT("PUT"),
+
+ /**
+ * 搜寻 @AnonymousPatchMapping
+ */
+ PATCH("PATCH"),
+
+ /**
+ * 搜寻 @AnonymousDeleteMapping
+ */
+ DELETE("DELETE"),
+
+ /**
+ * 否则就是所有 Request 接口都放行
+ */
+ ALL("All");
+
+ /**
+ * Request 类型
+ */
+ private final String type;
+
+ public static RequestMethodEnum find(String type) {
+ for (RequestMethodEnum value : RequestMethodEnum.values()) {
+ if (value.getType().equals(type)) {
+ return value;
+ }
+ }
+ return ALL;
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/SystemConst.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/SystemConst.java
new file mode 100644
index 00000000..b24d16f7
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/constant/SystemConst.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.constant;
+
+/**
+ * 常用静态常量
+ */
+public interface SystemConst {
+ /**
+ * win 系统
+ */
+ String WIN = "win";
+
+ /**
+ * mac 系统
+ */
+ String MAC = "mac";
+
+ /**
+ * 请求头名称
+ */
+ String HEADER_NAME = "Authorization";
+
+ /**
+ * Token前缀
+ */
+ String TOKEN_PREFIX = "Bearer";
+
+ /**
+ * 小数点
+ */
+ String SYMBOL_DOT = ".";
+ String SYMBOL_EQUAL = "=";
+ String SYMBOL_ADD = "+";
+ String SYMBOL_SUBTRACT = "-";
+ String SYMBOL_AT = "@";
+ String PROPERTY_OS_NAME = "os.name";
+ String OS_NAME_WINDOWS = "Windows";
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/BeanLoadFinishListener.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/BeanLoadFinishListener.java
new file mode 100644
index 00000000..9769cda4
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/BeanLoadFinishListener.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.context;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.stereotype.Component;
+
+/**
+ * Bean加载完毕 监听
+ *
+ * @author odboy
+ * @date 2025-01-16
+ */
+@Slf4j
+@Component
+public class BeanLoadFinishListener implements ApplicationListener {
+ @Override
+ public void onApplicationEvent(ContextRefreshedEvent event) {
+ log.info("所有的Bean都加载完毕了");
+ }
+}
\ No newline at end of file
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/BootApplication.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/BootApplication.java
new file mode 100644
index 00000000..8d75b9c3
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/BootApplication.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.context;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.env.Environment;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 主要目的是输出应用的服务地址
+ *
+ * @author odboy
+ * @date 2024-04-20
+ */
+@Slf4j
+public class BootApplication {
+ @Bean
+ public CsSpringBeanHolder springBeanHolder() {
+ return new CsSpringBeanHolder();
+ }
+
+ protected static void inited(ConfigurableApplicationContext application) throws UnknownHostException {
+ Environment env = application.getEnvironment();
+ String ip = InetAddress.getLocalHost().getHostAddress();
+ String port = env.getProperty("server.port");
+ String path = StrUtil.isEmpty(env.getProperty("config.servlet.context-path")) ?
+ "" :
+ env.getProperty("config.servlet.context-path");
+ log.info(
+ "\n----------------------------------------------------------\n\t" +
+ "Application is running! Access URLs:\n\t" + "Local: \t\thttp://localhost:" + port + path + "/\n\t" +
+ "External: \thttp://" + ip + ":" + port + path + "/\n\t" + "Swagger文档: \thttp://" + ip + ":" + port +
+ path + "/doc.html\n" + "----------------------------------------------------------");
+ }
+}
\ No newline at end of file
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsRequestHolder.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsRequestHolder.java
new file mode 100644
index 00000000..e13fd661
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsRequestHolder.java
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.context;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+/**
+ * 获取 HttpServletRequest
+ */
+public class CsRequestHolder {
+
+ public static HttpServletRequest getHttpServletRequest() {
+ return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsScriptHelper.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsScriptHelper.java
new file mode 100644
index 00000000..5c5fc9d6
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsScriptHelper.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.context;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Scriptable;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 脚本工具
+ *
+ * @author odboy
+ * @date 2025-09-23
+ */
+@Slf4j
+@Component
+public class CsScriptHelper {
+ public Object evalObj(String script, Map args) {
+ try (Context rhino = Context.enter()) {
+ Scriptable scope = rhino.initStandardObjects();
+ bindArgumentsToScope(scope, args);
+ Object result = rhino.evaluateString(scope, script, "JavaScript", 1, null);
+ log.info("执行结果: {}", Context.toString(result));
+ return result;
+ }
+ }
+
+ private void bindArgumentsToScope(Scriptable scope, Map, ?> args) {
+ if (args == null) {
+ return;
+ }
+ for (Map.Entry, ?> entry : args.entrySet()) {
+ Object jsValue = Context.javaToJS(entry.getValue(), scope);
+ scope.put(entry.getKey().toString(), scope, jsValue);
+ }
+ }
+
+ private void bindArgumentsToScope(Scriptable scope, Object args) {
+ if (args == null) {
+ return;
+ }
+ // 单个对象参数
+ Object jsValue = Context.javaToJS(args, scope);
+ scope.put("args", scope, jsValue);
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsSpringBeanHolder.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsSpringBeanHolder.java
new file mode 100644
index 00000000..c6ae78bb
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/context/CsSpringBeanHolder.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.context;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Slf4j
+@SuppressWarnings({"unchecked", "all"})
+public class CsSpringBeanHolder implements ApplicationContextAware, DisposableBean {
+
+ private static ApplicationContext applicationContext = null;
+ private static final List CALL_BACKS = new ArrayList<>();
+ private static boolean addCallback = true;
+
+ /**
+ * 针对 某些初始化方法, 在SpringContextHolder 未初始化时 提交回调方法。 在SpringContextHolder 初始化后, 进行回调使用
+ *
+ * @param callBack 回调函数
+ */
+ public synchronized static void addCallBacks(CallBack callBack) {
+ if (addCallback) {
+ CsSpringBeanHolder.CALL_BACKS.add(callBack);
+ } else {
+ log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName());
+ callBack.executor();
+ }
+ }
+
+ /**
+ * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+ */
+ public static T getBean(String name) {
+ assertContextInjected();
+ return (T) applicationContext.getBean(name);
+ }
+
+ /**
+ * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+ */
+ public static T getBean(Class requiredType) {
+ assertContextInjected();
+ return applicationContext.getBean(requiredType);
+ }
+
+ /**
+ * 获取SpringBoot 配置信息
+ *
+ * @param property 属性key
+ * @param defaultValue 默认值
+ * @param requiredType 返回类型
+ * @return /
+ */
+ public static T getProperties(String property, T defaultValue, Class requiredType) {
+ T result = defaultValue;
+ try {
+ result = getBean(Environment.class).getProperty(property, requiredType);
+ } catch (Exception ignored) {
+ }
+ return result;
+ }
+
+ /**
+ * 获取SpringBoot 配置信息
+ *
+ * @param property 属性key
+ * @return /
+ */
+ public static String getProperties(String property) {
+ return getProperties(property, null, String.class);
+ }
+
+ /**
+ * 获取SpringBoot 配置信息
+ *
+ * @param property 属性key
+ * @param requiredType 返回类型
+ * @return /
+ */
+ public static T getProperties(String property, Class requiredType) {
+ return getProperties(property, null, requiredType);
+ }
+
+ /**
+ * 检查ApplicationContext不为空.
+ */
+ private static void assertContextInjected() {
+ if (applicationContext == null) {
+ throw new IllegalStateException(
+ "applicaitonContext属性未注入, 请在applicationContext" +
+ ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
+ }
+ }
+
+ /**
+ * 清除SpringContextHolder中的ApplicationContext为Null.
+ */
+ private static void clearHolder() {
+ log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
+ applicationContext = null;
+ }
+
+ @Override
+ public void destroy() {
+ CsSpringBeanHolder.clearHolder();
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if (CsSpringBeanHolder.applicationContext != null) {
+ log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" +
+ CsSpringBeanHolder.applicationContext);
+ }
+ CsSpringBeanHolder.applicationContext = applicationContext;
+ if (addCallback) {
+ for (CallBack callBack : CsSpringBeanHolder.CALL_BACKS) {
+ callBack.executor();
+ }
+ CALL_BACKS.clear();
+ }
+ CsSpringBeanHolder.addCallback = false;
+ }
+
+ /**
+ * 获取 @Service 的所有 bean 名称
+ *
+ * @return /
+ */
+ public static List getAllServiceBeanName() {
+ return new ArrayList<>(Arrays.asList(applicationContext.getBeanNamesForAnnotation(Service.class)));
+ }
+
+ interface CallBack {
+
+ /**
+ * 回调执行方法
+ */
+ void executor();
+
+ /**
+ * 本回调任务名称
+ *
+ * @return /
+ */
+ default String getCallBackName() {
+ return Thread.currentThread().getId() + ":" + this.getClass().getName();
+ }
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/doc/SwaggerConfig.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/doc/SwaggerConfig.java
new file mode 100644
index 00000000..1c79666c
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/doc/SwaggerConfig.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.doc;
+
+import cn.odboy.constant.SystemConst;
+import cn.odboy.framework.properties.AppProperties;
+import cn.odboy.util.CsAnonTagUtil;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
+import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * api页面 /doc.html
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+ @Value("${server.servlet.context-path:}")
+ private String apiPath;
+ @Autowired
+ private AppProperties properties;
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ @Bean
+ public Docket createRestApi() {
+ return new Docket(DocumentationType.SWAGGER_2).enable(properties.getSwagger().getEnabled())
+ .pathMapping("/")
+ .apiInfo(apiInfo())
+ .select()
+ .paths(PathSelectors.regex("^(?!/error).*"))
+ .paths(PathSelectors.any())
+ .build()
+ //添加登陆认证
+ .securitySchemes(securitySchemes())
+ .securityContexts(securityContexts());
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder().description("一个简单且易上手的自动化运维平台")
+ .title("CuteJava 接口文档")
+ .version("1.4.1")
+ .build();
+ }
+
+ private List securitySchemes() {
+ //设置请求头信息
+ List securitySchemes = new ArrayList<>();
+ ApiKey apiKey = new ApiKey(SystemConst.HEADER_NAME, SystemConst.HEADER_NAME, "header");
+ securitySchemes.add(apiKey);
+ return securitySchemes;
+ }
+
+ private List securityContexts() {
+ //设置需要登录认证的路径
+ List securityContexts = new ArrayList<>();
+ securityContexts.add(getContextByPath());
+ return securityContexts;
+ }
+
+ private SecurityContext getContextByPath() {
+ Set urls = CsAnonTagUtil.getAllAnonymousUrl(applicationContext);
+ urls = urls.stream().filter(url -> !"/".equals(url)).collect(Collectors.toSet());
+ String regExp = "^(?!" + apiPath + String.join("|" + apiPath, urls) + ").*$";
+ return SecurityContext.builder().securityReferences(defaultAuth()).operationSelector(o -> o.requestMappingPattern()
+ // 排除不需要认证的接口
+ .matches(regExp)).build();
+ }
+
+ private List defaultAuth() {
+ List securityReferences = new ArrayList<>();
+ AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+ AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+ authorizationScopes[0] = authorizationScope;
+ securityReferences.add(new SecurityReference(SystemConst.HEADER_NAME, authorizationScopes));
+ return securityReferences;
+ }
+
+ /**
+ * 解决Springfox与SpringBoot集成后, WebMvcRequestHandlerProvider和WebFluxRequestHandlerProvider冲突问题
+ *
+ * @return /
+ */
+ @Bean
+ @SuppressWarnings({"unchecked", "all"})
+ public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
+ return new BeanPostProcessor() {
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
+ customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
+ }
+ return bean;
+ }
+
+ private void customizeSpringfoxHandlerMappings(List mappings) {
+ List filteredMappings =
+ mappings.stream().filter(mapping -> mapping.getPatternParser() == null).collect(Collectors.toList());
+ mappings.clear();
+ mappings.addAll(filteredMappings);
+ }
+
+ private List getHandlerMappings(Object bean) {
+ Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
+ if (field != null) {
+ field.setAccessible(true);
+ try {
+ return (List) field.get(bean);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Failed to access handlerMappings field", e);
+ }
+ }
+ return Collections.emptyList();
+ }
+ };
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/BadRequestException.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/BadRequestException.java
new file mode 100644
index 00000000..9fa1d8d7
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/BadRequestException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.exception;
+
+import lombok.Getter;
+import org.springframework.http.HttpStatus;
+
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+
+/**
+ * 统一异常处理
+ */
+@Getter
+public class BadRequestException extends RuntimeException {
+
+ private Integer status = BAD_REQUEST.value();
+
+ public BadRequestException(String msg) {
+ super(msg);
+ }
+
+ public BadRequestException(HttpStatus status, String msg) {
+ super(msg);
+ this.status = status.value();
+ }
+
+ public BadRequestException(Throwable cause) {
+ super(cause.getMessage());
+ this.status = BAD_REQUEST.value();
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/ServerException.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/ServerException.java
new file mode 100644
index 00000000..3e061b6f
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/ServerException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.exception;
+
+import lombok.Getter;
+import org.springframework.http.HttpStatus;
+
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+
+@Getter
+public class ServerException extends RuntimeException {
+
+ private Integer status = INTERNAL_SERVER_ERROR.value();
+
+ public ServerException(String msg) {
+ super(msg);
+ }
+
+ public ServerException(HttpStatus status, String msg) {
+ super(msg);
+ this.status = status.value();
+ }
+
+ public ServerException(Throwable cause) {
+ super(cause.getMessage());
+ this.status = INTERNAL_SERVER_ERROR.value();
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/handler/ApiError.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/handler/ApiError.java
new file mode 100644
index 00000000..c941a029
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/handler/ApiError.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.exception.handler;
+
+import lombok.Data;
+
+@Data
+public final class ApiError {
+
+ private Integer status = 400;
+ private Long timestamp;
+ private String message;
+
+ private ApiError() {
+ timestamp = System.currentTimeMillis();
+ }
+
+ public static ApiError error(final String message) {
+ ApiError apiError = new ApiError();
+ apiError.setMessage(message);
+ return apiError;
+ }
+
+ public static ApiError error(final Integer status, final String message) {
+ ApiError apiError = new ApiError();
+ apiError.setStatus(status);
+ apiError.setMessage(message);
+ return apiError;
+ }
+}
+
+
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/handler/GlobalExceptionHandler.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/handler/GlobalExceptionHandler.java
new file mode 100644
index 00000000..15e26ece
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/exception/handler/GlobalExceptionHandler.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.exception.handler;
+
+import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.odboy.framework.exception.BadRequestException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.validation.FieldError;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+/**
+ * 全局异常处理
+ *
+ * @author odboy
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ /**
+ * 处理所有不可知的异常
+ */
+ @ExceptionHandler(Throwable.class)
+ public ResponseEntity handleException(Throwable e) {
+ // 打印堆栈信息
+ log.error(ExceptionUtil.stacktraceToString(e));
+ return buildResponseEntity(ApiError.error(e.getMessage()));
+ }
+
+ /**
+ * BadCredentialsException
+ */
+ @ExceptionHandler(BadCredentialsException.class)
+ public ResponseEntity badCredentialsException(BadCredentialsException e) {
+ // 打印堆栈信息
+ String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage();
+ log.error(message);
+ return buildResponseEntity(ApiError.error(message));
+ }
+
+ /**
+ * 处理自定义异常
+ */
+ @ExceptionHandler(value = BadRequestException.class)
+ public ResponseEntity badRequestException(BadRequestException e) {
+ // 打印堆栈信息
+ log.error(ExceptionUtil.stacktraceToString(e));
+ return buildResponseEntity(ApiError.error(e.getStatus(), e.getMessage()));
+ }
+
+ /**
+ * 处理所有接口数据验证异常
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+ // 打印堆栈信息
+ log.error(ExceptionUtil.stacktraceToString(e));
+ ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
+ String message = objectError.getDefaultMessage();
+ if (objectError instanceof FieldError) {
+ message = ((FieldError) objectError).getField() + ": " + message;
+ }
+ return buildResponseEntity(ApiError.error(message));
+ }
+
+ /**
+ * 统一返回
+ */
+ private ResponseEntity buildResponseEntity(ApiError apiError) {
+ return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus()));
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/logging/ExecutionTimeStatisticsFace.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/logging/ExecutionTimeStatisticsFace.java
new file mode 100644
index 00000000..c1f67785
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/logging/ExecutionTimeStatisticsFace.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.logging;
+
+import java.lang.annotation.*;
+
+/**
+ * 统计执行时长
+ *
+ * @author odboy
+ */
+@Inherited
+@Documented
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExecutionTimeStatisticsFace {
+ /**
+ * 接口描述
+ */
+ String description();
+
+ /**
+ * 是否展示异常日志
+ */
+ boolean showErrLog() default true;
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/logging/ExecutionTimeStatisticsFaceAspect.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/logging/ExecutionTimeStatisticsFaceAspect.java
new file mode 100644
index 00000000..bcd41cda
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/logging/ExecutionTimeStatisticsFaceAspect.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.logging;
+
+import cn.hutool.core.date.TimeInterval;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+
+/**
+ * 执行时间统计
+ *
+ * @author odboy
+ * @date 2025-05-07
+ */
+@Slf4j
+@Aspect
+@Component
+public class ExecutionTimeStatisticsFaceAspect {
+ @Around("@annotation(executionTimeStatisticsFace)")
+ public Object aroundFace(ProceedingJoinPoint joinPoint, ExecutionTimeStatisticsFace executionTimeStatisticsFace) throws Throwable {
+ TimeInterval timeInterval = new TimeInterval();
+ try {
+ Object proceed = joinPoint.proceed();
+ log.info("[{}] 接口执行成功,耗时: {} ms", executionTimeStatisticsFace.description(), timeInterval.intervalMs());
+ return proceed;
+ } catch (Exception e) {
+ if (executionTimeStatisticsFace.showErrLog()) {
+ log.error("[{}] 接口执行失败,耗时: {} ms", executionTimeStatisticsFace.description(), timeInterval.intervalMs(), e);
+ }
+ throw e;
+ }
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/monitor/controller/HealthCheckController.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/monitor/controller/HealthCheckController.java
new file mode 100644
index 00000000..05452d20
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/monitor/controller/HealthCheckController.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.monitor.controller;
+
+import cn.odboy.annotation.AnonymousGetMapping;
+import cn.odboy.framework.monitor.service.CsHealthCheckPointService;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 健康检查接口
+ */
+@RestController
+@RequestMapping("/healthCheck")
+@Api(tags = "系统:健康检查接口")
+public class HealthCheckController {
+ @Autowired
+ private CsHealthCheckPointService healthCheckPointService;
+
+ /**
+ * 就绪检查
+ */
+ @AnonymousGetMapping(value = "/readiness")
+ public ResponseEntity> doReadiness() {
+ return healthCheckPointService.doReadiness();
+ }
+
+ /**
+ * 存活检查
+ */
+ @AnonymousGetMapping(value = "/liveness")
+ public ResponseEntity> doLiveness() {
+ return healthCheckPointService.doLiveness();
+ }
+
+ // /**
+ // * 访问首页提示
+ // */
+ // @AnonymousGetMapping("/")
+ // public String index() {
+ // return "success";
+ // }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/monitor/service/CsHealthCheckPointService.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/monitor/service/CsHealthCheckPointService.java
new file mode 100644
index 00000000..8e9ef84e
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/monitor/service/CsHealthCheckPointService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.monitor.service;
+
+import org.springframework.http.ResponseEntity;
+
+public interface CsHealthCheckPointService {
+ /**
+ * 就绪检查
+ */
+ ResponseEntity> doReadiness();
+
+ /**
+ * 存活检查
+ */
+ ResponseEntity> doLiveness();
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/CsMpQTypeEnum.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/CsMpQTypeEnum.java
new file mode 100644
index 00000000..58dd26ea
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/CsMpQTypeEnum.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.config;
+
+/**
+ * 动态查询 枚举
+ */
+public enum CsMpQTypeEnum {
+ /**
+ * 相等
+ */
+ EQUAL
+ /**
+ * 大于等于
+ */
+ ,
+ GREATER_THAN
+ /**
+ * 小于等于
+ */
+ ,
+ LESS_THAN
+ /**
+ * 中模糊查询
+ */
+ ,
+ INNER_LIKE
+ /**
+ * 左模糊查询
+ */
+ ,
+ LEFT_LIKE
+ /**
+ * 右模糊查询
+ */
+ ,
+ RIGHT_LIKE
+ /**
+ * 小于
+ */
+ ,
+ LESS_THAN_NQ
+ /**
+ * 包含
+ */
+ ,
+ IN
+ /**
+ * 不包含
+ */
+ ,
+ NOT_IN
+ /**
+ * 不等于
+ */
+ ,
+ NOT_EQUAL
+ /**
+ * between(注:被注解的属性一定得是数组或者集合, 长度大于等于2)
+ */
+ ,
+ BETWEEN
+ /**
+ * 不为空
+ */
+ ,
+ NOT_NULL
+ /**
+ * 为空
+ */
+ ,
+ IS_NULL
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/CsMpQuery.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/CsMpQuery.java
new file mode 100644
index 00000000..b04428b6
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/CsMpQuery.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 查询描述
+ *
+ * @date 2023-11-25
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CsMpQuery {
+ /**
+ * 基本对象的属性名
+ */
+ String propName() default "";
+
+ /**
+ * 查询方式
+ */
+ CsMpQTypeEnum type() default CsMpQTypeEnum.EQUAL;
+
+ /**
+ * 多字段模糊搜索, 仅支持String类型字段, 多个用逗号隔开, 如@MpQuery(blurry = "email,username")
+ */
+ String blurry() default "";
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/DataTypeEnum.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/DataTypeEnum.java
new file mode 100644
index 00000000..3dd71287
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/DataTypeEnum.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.config;
+
+import cn.odboy.framework.exception.BadRequestException;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author /
+ */
+@Slf4j
+@SuppressWarnings({"unchecked", "all"})
+public enum DataTypeEnum {
+ /**
+ * mysql
+ */
+ MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"),
+ /**
+ * oracle
+ */
+ ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""),
+ /**
+ * sql config
+ */
+ SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""),
+ /**
+ * h2
+ */
+ H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""),
+ /**
+ * phoenix
+ */
+ PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""),
+ /**
+ * mongo
+ */
+ MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""),
+ /**
+ * sql4es
+ */
+ ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"),
+ /**
+ * presto
+ */
+ PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""),
+ /**
+ * moonbox
+ */
+ MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"),
+ /**
+ * cassandra
+ */
+ CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"),
+ /**
+ * click house
+ */
+ CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""),
+ /**
+ * kylin
+ */
+ KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""),
+ /**
+ * vertica
+ */
+ VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"),
+ /**
+ * sap
+ */
+ HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"),
+ /**
+ * impala
+ */
+ IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'");
+ private String feature;
+ private String desc;
+ private String driver;
+ private String keywordPrefix;
+ private String keywordSuffix;
+ private String aliasPrefix;
+ private String aliasSuffix;
+ private static final String JDBC_URL_PREFIX = "jdbc:";
+
+ DataTypeEnum(
+ String feature,
+ String desc,
+ String driver,
+ String keywordPrefix,
+ String keywordSuffix,
+ String aliasPrefix,
+ String aliasSuffix) {
+ this.feature = feature;
+ this.desc = desc;
+ this.driver = driver;
+ this.keywordPrefix = keywordPrefix;
+ this.keywordSuffix = keywordSuffix;
+ this.aliasPrefix = aliasPrefix;
+ this.aliasSuffix = aliasSuffix;
+ }
+
+ public static DataTypeEnum urlOf(String jdbcUrl) {
+ String url = jdbcUrl.toLowerCase().trim();
+ for (DataTypeEnum dataTypeEnum : values()) {
+ if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) {
+ try {
+ Class> aClass = Class.forName(dataTypeEnum.getDriver());
+ if (null == aClass) {
+ throw new BadRequestException("Unable to get driver instance for jdbcUrl: " + jdbcUrl);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new BadRequestException("Unable to get driver instance: " + jdbcUrl);
+ }
+ return dataTypeEnum;
+ }
+ }
+ return null;
+ }
+
+ public String getFeature() {
+ return feature;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public String getDriver() {
+ return driver;
+ }
+
+ public String getKeywordPrefix() {
+ return keywordPrefix;
+ }
+
+ public String getKeywordSuffix() {
+ return keywordSuffix;
+ }
+
+ public String getAliasPrefix() {
+ return aliasPrefix;
+ }
+
+ public String getAliasSuffix() {
+ return aliasSuffix;
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MpCustomP6SpyLogger.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MpCustomP6SpyLogger.java
new file mode 100644
index 00000000..7e6e8e89
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MpCustomP6SpyLogger.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 自定义 p6spy sql输出格式
+ */
+@Slf4j
+public class MpCustomP6SpyLogger implements MessageFormattingStrategy {
+ /**
+ * 重置颜色
+ */
+ private static final String RESET = "\u001B[0m";
+ /**
+ * 红色
+ */
+ private static final String RED = "\u001B[31m";
+ /**
+ * 绿色
+ */
+ private static final String GREEN = "\u001B[32m";
+ /**
+ * 蓝色
+ */
+ private static final String BLUE = "\u001B[34m";
+
+ /**
+ * 格式化 sql
+ *
+ * @param connectionId 连接id
+ * @param now 当前时间
+ * @param elapsed 执行时长
+ * @param category sql分类
+ * @param prepared 预编译sql
+ * @param sql 执行sql
+ * @param url 数据库连接url
+ * @return 格式化后的sql
+ */
+ @Override
+ public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
+ // 去掉换行和多余空格
+ if (StrUtil.isNotBlank(sql)) {
+ sql = sql.replaceAll("\\s+", " ").trim();
+ }
+ // 格式化并加上颜色
+ return String.format("CuteJava - %s%s%s %s[%s] %sREVIEW_SQL [Interval: %dms]%s -> %s;", RED, now, RESET, GREEN, Thread.currentThread().getName(), BLUE, elapsed, RESET, sql);
+ }
+}
\ No newline at end of file
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MpInsertBatchSqlInjector.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MpInsertBatchSqlInjector.java
new file mode 100644
index 00000000..88c8402e
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MpInsertBatchSqlInjector.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.config;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.core.injector.AbstractMethod;
+import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById;
+import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
+import org.apache.ibatis.session.Configuration;
+
+import java.util.List;
+
+/**
+ * 批量插入SQL注入器
+ *
+ * @author odboy
+ * @date 2025-01-11
+ */
+public class MpInsertBatchSqlInjector extends DefaultSqlInjector {
+ @Override
+ public List getMethodList(Configuration configuration, Class> mapperClass, TableInfo tableInfo) {
+ List methodList = super.getMethodList(configuration, mapperClass, tableInfo);
+ // 新增自定义方法, InsertBatchSomeColumn这个方法Mp没有开放出来
+ methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
+ // 全量更新, 包括null字段
+ methodList.add(new AlwaysUpdateSomeColumnById(i -> i.getFieldFill() != FieldFill.INSERT));
+ return methodList;
+ }
+}
\ No newline at end of file
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MybatisPlusConfig.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MybatisPlusConfig.java
new file mode 100644
index 00000000..86243018
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/MybatisPlusConfig.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@EnableTransactionManagement
+public class MybatisPlusConfig {
+ @Bean
+ public MybatisPlusInterceptor paginationInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ // MySQL的分页拦截器
+ PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
+ paginationInnerInterceptor.setMaxLimit(500L);
+ /// 这个配置会导致:当分页没数据时, 游标从0开始,会导致无论page为什么值,就算分页超出最大页数,依然能够查询到
+ /// paginationInnerInterceptor.setOverflow(true);
+ paginationInnerInterceptor.setOptimizeJoin(true);
+ interceptor.addInnerInterceptor(paginationInnerInterceptor);
+ // 乐观锁
+ interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
+ // 防全表更新与删除
+ interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
+ return interceptor;
+ }
+
+ /**
+ * Mapper支持批量插入
+ */
+ @Bean
+ public MpInsertBatchSqlInjector insertBatchSqlInjector() {
+ return new MpInsertBatchSqlInjector();
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/RemoveDruidAdConfig.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/RemoveDruidAdConfig.java
new file mode 100644
index 00000000..72dc7f02
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/config/RemoveDruidAdConfig.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.config;
+
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
+import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
+import com.alibaba.druid.util.Utils;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Configuration
+@SuppressWarnings({"unchecked", "all"})
+@ConditionalOnWebApplication
+@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
+@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true", matchIfMissing = true)
+public class RemoveDruidAdConfig {
+
+ /**
+ * 方法名: removeDruidAdFilterRegistrationBean 方法描述 除去页面底部的广告
+ *
+ * @param properties com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties
+ * @return org.springframework.boot.web.servlet.FilterRegistrationBean
+ */
+ @Bean
+ public FilterRegistrationBean removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
+
+ // 获取web监控页面的参数
+ DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
+ // 提取common.js的配置路径
+ String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
+ String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
+
+ final String filePath = "support/http/resources/js/common.js";
+
+ //创建filter进行过滤
+ Filter filter = new Filter() {
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ if (httpRequest.getRequestURI().endsWith("js/common.js")) {
+ // 获取common.js
+ String text = Utils.readFromResource(filePath);
+ // 正则替换banner, 除去底部的广告信息
+ text = text.replaceAll(" ", "");
+ text = text.replaceAll("powered by.*?shrek.wang", "");
+ httpResponse.setContentType("application/javascript");
+ httpResponse.setCharacterEncoding("UTF-8");
+ httpResponse.getWriter().write(text);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+ };
+ FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+ registrationBean.setFilter(filter);
+ registrationBean.addUrlPatterns(commonJsPattern);
+ return registrationBean;
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpAnyQUtil.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpAnyQUtil.java
new file mode 100644
index 00000000..eac33991
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpAnyQUtil.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.core;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 自定义任意对象查询工具
+ *
+ * @author odboy
+ * @date 2025-05-15
+ */
+public class CsMpAnyQUtil {
+ public static T selectOne(BaseMapper baseMapper, Object queryParams) {
+ QueryWrapper queryWrapper = CsMpQUtil.build(queryParams);
+ return baseMapper.selectOne(queryWrapper);
+ }
+
+ public static M selectOne(BaseMapper baseMapper, Object queryParams, Class mapperClazz) {
+ QueryWrapper queryWrapper = CsMpQUtil.build(queryParams);
+ T mapperTarget = baseMapper.selectOne(queryWrapper);
+ if (mapperTarget == null) {
+ return null;
+ }
+ return BeanUtil.copyProperties(mapperTarget, mapperClazz);
+ }
+
+ public static List selectList(BaseMapper baseMapper, Object queryParams) {
+ QueryWrapper queryWrapper = CsMpQUtil.build(queryParams);
+ return baseMapper.selectList(queryWrapper);
+ }
+
+ public static List selectList(BaseMapper baseMapper, Object queryParams, Class mapperClazz) {
+ QueryWrapper queryWrapper = CsMpQUtil.build(queryParams);
+ List mapperTarget = baseMapper.selectList(queryWrapper);
+ if (mapperTarget == null) {
+ return new ArrayList<>();
+ }
+ return BeanUtil.copyToList(mapperTarget, mapperClazz);
+ }
+
+ public static Long selectCount(BaseMapper baseMapper, Object queryParams) {
+ QueryWrapper queryWrapper = CsMpQUtil.build(queryParams);
+ return baseMapper.selectCount(queryWrapper);
+ }
+
+ public static Page selectPage(BaseMapper baseMapper, Page page, Object queryParams) {
+ QueryWrapper queryWrapper = CsMpQUtil.build(queryParams);
+ return baseMapper.selectPage(page, queryWrapper);
+ }
+
+ public static Page selectPage(
+ BaseMapper baseMapper,
+ Page page,
+ Object queryParams,
+ Class mapperClazz) {
+ QueryWrapper queryWrapper = CsMpQUtil.build(queryParams);
+ Page tPage = baseMapper.selectPage(page, queryWrapper);
+ Page mapperTarget = new Page<>();
+ mapperTarget.setRecords(BeanUtil.copyToList(tPage.getRecords(), mapperClazz));
+ mapperTarget.setTotal(tPage.getTotal());
+ mapperTarget.setSize(tPage.getSize());
+ mapperTarget.setCurrent(tPage.getCurrent());
+ return mapperTarget;
+ }
+}
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpCmdGenUtil.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpCmdGenUtil.java
new file mode 100644
index 00000000..33460b45
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpCmdGenUtil.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.core;
+
+import cn.hutool.core.util.StrUtil;
+import cn.odboy.base.CsBaseUserTimeTb;
+import cn.odboy.framework.exception.BadRequestException;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
+import com.baomidou.mybatisplus.generator.config.rules.DateType;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
+import lombok.Data;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.sql.Types;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * 代码生成器入口
+ *
+ * @author odboy
+ * @date 2025-01-11
+ */
+@Data
+public class CsMpCmdGenUtil {
+ // 项目根路径。生成结果 C:\Users\Administrator\Documents\GitHub\cutejava\cutejava
+ private static final String projectRootPath = System.getProperty("user.dir") + "/";
+ /**
+ * 数据库类型 MySQL
+ */
+ private static final IDbQuery DB_QUERY = new MySqlQuery();
+ /**
+ * 类型转换
+ */
+ private static final String TYPE_TINY_INT = "tinyint";
+ private static final String TYPE_DATETIME = "datetime";
+ private static final String TYPE_DATE = "date";
+ private String databaseUrl;
+ private String databaseUsername;
+ private String databasePassword;
+ private String driverClassName;
+ private String parentPackageName = "cn.odboy";
+ private String parentModuleName;
+
+ /**
+ * 代码生成函数
+ *
+ * @param moduleName 模块名称
+ * @param tablePrefix 表前缀(可空)
+ * @param tableNames 表名称, 多个用逗号分隔
+ */
+ public void gen(String moduleName, String tablePrefix, List tableNames) {
+ this.parentModuleName = moduleName;
+ // 1.数据库配置
+ DataSourceConfig.Builder dataSourceConfigBuilder =
+ new DataSourceConfig.Builder(this.databaseUrl, this.databaseUsername, this.databasePassword).driverClassName(
+ this.driverClassName);
+ dataSourceConfigBuilder.dbQuery(DB_QUERY);
+ dataSourceConfigBuilder.keyWordsHandler(new MySqlKeyWordsHandler());
+ // 1.1.快速生成器
+ FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(dataSourceConfigBuilder);
+ // 2.全局配置
+ // 自定义类型转换
+ fastAutoGenerator.dataSourceConfig(getDataSourceConfigConsumer());
+ // 覆盖已生成文件
+ // 添加swagger注解
+ // 设置注释的作者
+ // 设置注释的日期格式
+ // 使用java8新的时间类型
+ fastAutoGenerator.globalConfig(getGlobalConfigConsumer());
+ // 3.包配置
+ // 设置父包名
+ // 设置父包模块名
+ // 设置MVC下各个模块的包名
+ // 设置XML资源文件的目录
+ fastAutoGenerator.packageConfig(getPackageConfigConsumer());
+ // 4.模板配置
+ // 使用Freemarker引擎模板, 默认的是Velocity引擎模板
+ AbstractTemplateEngine templateEngine = new FreemarkerTemplateEngine();
+ fastAutoGenerator.templateEngine(templateEngine);
+ // 5.策略配置
+ // 设置需要生成的表名
+ // 设置过滤表前缀
+ fastAutoGenerator.strategyConfig(getStrategyConfigConsumer(tableNames));
+ if (tablePrefix != null) {
+ // 表前缀, 可多个
+ fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.addTablePrefix(tablePrefix));
+ }
+ // 5.1.Entity策略配置
+ // 生成实体时生成字段的注解, 包括@TableId注解等
+ // 数据库表和字段映射到实体的命名策略, 为下划线转驼峰
+ // 全局主键类型为None
+ // 实体名称格式化为XXXEntity
+ fastAutoGenerator.strategyConfig(getEntityConfigConsumer());
+ // 5.2.Controller策略配置
+ // 开启生成@RestController控制器
+ fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.controllerBuilder()
+ .enableRestStyle());
+ // 如果不需要生成Controller, fastAutoGenerator.templateConfig(templateConfig -> templateConfig.controller(""))。5.3.Service策略配置:格式化service接口和实现类的文件名称, 去掉默认的ServiceName前面的I
+ fastAutoGenerator.strategyConfig(
+ strategyConfigBuilder -> strategyConfigBuilder.serviceBuilder()
+ .formatServiceFileName("%sService")
+ .formatServiceImplFileName("%sServiceImpl"));
+ // 5.4.Mapper策略配置
+ // 格式化 mapper文件名,格式化xml实现类文件名称
+ fastAutoGenerator.strategyConfig(getStrategyConfigConsumer());
+ // 6.生成代码
+ fastAutoGenerator.execute();
+ }
+
+ private static Consumer getEntityConfigConsumer() {
+ return strategyConfigBuilder -> strategyConfigBuilder.entityBuilder()
+ .enableLombok()
+ // 如果不需要生成注解, 去掉.enableTableFieldAnnotation()
+ .enableTableFieldAnnotation()
+ .enableFileOverride()
+ .naming(NamingStrategy.underline_to_camel)
+ .columnNaming(NamingStrategy.underline_to_camel)
+ .idType(IdType.AUTO);
+ }
+
+ private static Consumer getStrategyConfigConsumer(List tableNames) {
+ return strategyConfigBuilder -> strategyConfigBuilder.enableCapitalMode()
+ .enableSkipView()
+ .disableSqlFilter()
+ .addInclude(tableNames)
+ // 实体类生成策略
+ .entityBuilder()
+ .superClass(CsBaseUserTimeTb.class)
+ .addIgnoreColumns("create_time", "update_time", "create_by", "update_by")
+ // 开启生成实体时生成字段注解。
+ // 会在实体类的属性前,添加[@TableField("nickname")]
+ .enableTableFieldAnnotation()
+ .disableSerialVersionUID()
+ // 阶段2:Mapper策略配置
+ .mapperBuilder()
+ // 开启 @Mapper 注解。
+ // 会在mapper接口上添加注解[@Mapper]
+ // .enableMapperAnnotation()
+ // 启用 BaseResultMap 生成。
+ // 会在mapper.xml文件生成[通用查询映射结果]配置。
+ // .enableBaseResultMap()
+ // 启用 BaseColumnList。
+ // 会在mapper.xml文件生成[通用查询结果列 ]配置
+ // .enableBaseColumnList()
+ // 阶段4:Controller策略配置
+ .controllerBuilder()
+ // 会在控制类中加[@RestController]注解。
+ .enableRestStyle()
+ // 开启驼峰转连字符
+ .enableHyphenStyle()
+ .build();
+ }
+
+ private Consumer getPackageConfigConsumer() {
+ String mapperPath = projectRootPath + "CodeGen/resources/mapper";
+ if (StrUtil.isBlank(this.parentModuleName)) {
+ throw new BadRequestException("模块名称必填");
+ }
+ return packageConfigBuilder -> packageConfigBuilder.parent(this.parentPackageName)
+ .moduleName(this.parentModuleName)
+ .entity("dal.dataobject")
+ .mapper("dal.mysql")
+ .service("service")
+ .serviceImpl("service.impl")
+ .controller("controller")
+ .pathInfo(Collections.singletonMap(OutputFile.xml, mapperPath));
+ }
+
+ private static Consumer getGlobalConfigConsumer() {
+ String outputDir = projectRootPath + "CodeGen";
+ return globalConfigBuilder -> globalConfigBuilder.enableSwagger()
+ .outputDir(outputDir)
+ .author("codegen")
+ .commentDate("yyyy-MM-dd")
+ .dateType(DateType.TIME_PACK);
+ }
+
+ private static Consumer getStrategyConfigConsumer() {
+ return strategyConfigBuilder -> strategyConfigBuilder.mapperBuilder()
+ .mapperAnnotation(Mapper.class)
+ .formatMapperFileName("%sMapper")
+ .formatXmlFileName("%sMapper")
+ .entityBuilder()
+ .formatFileName("%sTb");
+ }
+
+ private static Consumer getDataSourceConfigConsumer() {
+ return builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
+ int typeCode = metaInfo.getJdbcType().TYPE_CODE;
+ if (typeCode == Types.SMALLINT) {
+ return DbColumnType.INTEGER;
+ }
+ if (typeCode == Types.DATE) {
+ return DbColumnType.DATE;
+ }
+ if (typeCode == Types.TIME) {
+ return DbColumnType.DATE;
+ }
+ if (typeCode == Types.TIMESTAMP) {
+ return DbColumnType.DATE;
+ }
+ return typeRegistry.getColumnType(metaInfo);
+ });
+ }
+}
\ No newline at end of file
diff --git a/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpQUtil.java b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpQUtil.java
new file mode 100644
index 00000000..ad5317be
--- /dev/null
+++ b/cutejava-springboot3/cutejava-framework/src/main/java/cn/odboy/framework/mybatisplus/core/CsMpQUtil.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2021-2025 Odboy
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.odboy.framework.mybatisplus.core;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.odboy.base.CsBaseUserTimeTb;
+import cn.odboy.framework.exception.BadRequestException;
+import cn.odboy.framework.mybatisplus.config.CsMpQuery;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 查询条件创建工具
+ */
+@Slf4j
+public class CsMpQUtil {
+ public static QueryWrapper build(Q query) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ if (query == null) {
+ return queryWrapper;
+ }
+ Class> clazz = query.getClass();
+ try {
+ List fields = getAllFields(clazz, new ArrayList<>());
+ for (Field field : fields) {
+ if (!field.canAccess(query)) {
+ field.setAccessible(true);
+ CsMpQuery q = field.getAnnotation(CsMpQuery.class);
+ if (q != null) {
+ String attributeName = getAttributeName(q, field);
+ Object fieldVal = field.get(query);
+ if (ObjectUtil.isNull(fieldVal) || "".equals(fieldVal)) {
+ continue;
+ }
+ if (StrUtil.isNotBlank(q.blurry())) {
+ handleBlurryQuery(queryWrapper, q.blurry(), fieldVal);
+ continue;
+ }
+ handleWrapper(q, queryWrapper, attributeName, fieldVal);
+ }
+ field.setAccessible(false);
+ }
+ }
+ } catch (Exception e) {
+ log.error("Failed to build query wrapper for class: {}", clazz.getName(), e);
+ }
+ return queryWrapper;
+ }
+
+ private static String getAttributeName(CsMpQuery q, Field field) {
+ String attributeName = StrUtil.isBlank(q.propName()) ? field.getName() : q.propName();
+ return StrUtil.toUnderlineCase(attributeName);
+ }
+
+ private static void handleWrapper(
+ CsMpQuery q,
+ QueryWrapper queryWrapper,
+ String attributeName,
+ Object fieldVal) {
+ switch (q.type()) {
+ case EQUAL:
+ queryWrapper.eq(attributeName, fieldVal);
+ break;
+ case GREATER_THAN:
+ queryWrapper.ge(attributeName, fieldVal);
+ break;
+ case LESS_THAN:
+ queryWrapper.le(attributeName, fieldVal);
+ break;
+ case LESS_THAN_NQ:
+ queryWrapper.lt(attributeName, fieldVal);
+ break;
+ case INNER_LIKE:
+ queryWrapper.like(attributeName, fieldVal);
+ break;
+ case LEFT_LIKE:
+ queryWrapper.likeLeft(attributeName, fieldVal);
+ break;
+ case RIGHT_LIKE:
+ queryWrapper.likeRight(attributeName, fieldVal);
+ break;
+ case IN:
+ handleInOrNotQuery(true, queryWrapper, attributeName, fieldVal);
+ break;
+ case NOT_IN:
+ handleInOrNotQuery(false, queryWrapper, attributeName, fieldVal);
+ break;
+ case NOT_EQUAL:
+ queryWrapper.ne(attributeName, fieldVal);
+ break;
+ case NOT_NULL:
+ queryWrapper.isNotNull(attributeName);
+ break;
+ case IS_NULL:
+ queryWrapper.isNull(attributeName);
+ break;
+ case BETWEEN:
+ handleBetweenQuery(queryWrapper, fieldVal, attributeName);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private static void handleInOrNotQuery(
+ boolean b,
+ QueryWrapper queryWrapper,
+ String attributeName,
+ Object fieldVal) {
+ Collection> wrapNotInVal = (Collection>) fieldVal;
+ if (CollectionUtil.isNotEmpty(wrapNotInVal)) {
+ Optional> anyValOptional = wrapNotInVal.stream().findAny();
+ if (anyValOptional.isPresent()) {
+ Object o = anyValOptional.get();
+ if (o instanceof Long) {
+ if (b) {
+ queryWrapper.in(attributeName, fieldVal);
+ } else {
+ queryWrapper.notIn(attributeName, fieldVal);
+ }
+ } else if (o instanceof Integer) {
+ if (b) {
+ queryWrapper.in(attributeName, fieldVal);
+ } else {
+ queryWrapper.notIn(attributeName, fieldVal);
+ }
+ } else {
+ throw new BadRequestException("InOrNotIn查询参数类型的对象属性值必须是Long/Integer类型集合");
+ }
+ }
+ }
+ }
+
+ private static void handleBetweenQuery(QueryWrapper queryWrapper, Object fieldVal, String finalAttributeName) {
+ if (fieldVal instanceof List) {
+ List