From ba04a1047ba6a6d3c05b62a8af7cc19f8c8f75c8 Mon Sep 17 00:00:00 2001
From: liujing33 <114553116+liujing33@users.noreply.github.com>
Date: Thu, 8 May 2025 18:02:47 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 3 +
LICENSE | 201 -------------
pom.xml | 66 +++++
reactive-programming/pom.xml | 50 ++++
.../ReactiveProgrammingApplication.java | 15 +
.../mangmang/controller/HelloController.java | 12 +
.../controller/ProductController.java | 74 +++++
.../java/org/mangmang/entity/Product.java | 15 +
.../repository/ProductRepository.java | 9 +
.../org/mangmang/service/ProductService.java | 39 +++
.../src/main/resources/application.yml | 0
spring-cloud-demo/config-server/pom.xml | 34 +++
.../com/mangmang/ConfigServerApplication.java | 19 ++
.../src/main/resources/application.yml | 27 ++
spring-cloud-demo/eureka-server/pom.xml | 33 +++
.../com/mangmang/EurekaServerApplication.java | 17 ++
.../src/main/resources/application.yml | 21 ++
spring-cloud-demo/gateway-service/pom.xml | 46 +++
.../mangmang/GatewayServiceApplication.java | 17 ++
.../src/main/resources/application.yml | 49 ++++
.../src/main/resources/bootstrap.yml | 18 ++
spring-cloud-demo/order-service/pom.xml | 55 ++++
.../com/mangmang/OrderServiceApplication.java | 16 ++
.../orderservice/client/UserClient.java | 13 +
.../orderservice/client/model/Order.java | 15 +
.../orderservice/client/model/User.java | 10 +
.../controller/OrderController.java | 65 +++++
.../src/main/resources/application.yml | 19 ++
.../src/main/resources/bootstrap.yml | 18 ++
spring-cloud-demo/pom.xml | 34 +++
spring-cloud-demo/user-service/pom.xml | 53 ++++
.../com/mangmang/UserServiceApplication.java | 16 ++
.../mangmang/controller/UserController.java | 43 +++
.../main/java/com/mangmang/entity/User.java | 14 +
.../src/main/resources/application.yml | 19 ++
.../src/main/resources/bootstrap.yml | 19 ++
spring-data-jpa-read-write-separation/pom.xml | 41 +++
...DataJpaReadWriteSeparationApplication.java | 12 +
.../com/mangmang/annotaion/DataSource.java | 5 +
.../mangmang/annotaion/TargetDataSource.java | 24 ++
.../com/mangmang/config/DataSourceAspect.java | 79 ++++++
.../com/mangmang/config/DataSourceConfig.java | 75 +++++
.../mangmang/config/DynamicDataSource.java | 52 ++++
.../mangmang/controller/UserController.java | 38 +++
.../main/java/com/mangmang/entity/User.java | 22 ++
.../mangmang/repository/UserRepository.java | 9 +
.../com/mangmang/service/UserService.java | 15 +
.../service/impl/UserServiceImpl.java | 45 +++
.../src/main/resources/application.yml | 19 ++
swing-and-javafx/pom.xml | 47 +++
.../java/com/mangmang/HelloWordSwing.java | 29 ++
.../main/java/com/mangmang/HelloWorldFX.java | 28 ++
.../java/com/mangmang/ImageConverterApp.java | 267 ++++++++++++++++++
websocket/pom.xml | 31 ++
.../mangmang/WebSocketDemoApplication.java | 13 +
.../com/mangmang/config/WebSocketConfig.java | 27 ++
.../controller/MessageController.java | 36 +++
.../listener/WebSocketEventListener.java | 43 +++
.../main/java/com/mangmang/model/Message.java | 25 ++
websocket/src/main/resources/application.yml | 6 +
60 files changed, 1961 insertions(+), 201 deletions(-)
delete mode 100644 LICENSE
create mode 100644 pom.xml
create mode 100644 reactive-programming/pom.xml
create mode 100644 reactive-programming/src/main/java/org/mangmang/ReactiveProgrammingApplication.java
create mode 100644 reactive-programming/src/main/java/org/mangmang/controller/HelloController.java
create mode 100644 reactive-programming/src/main/java/org/mangmang/controller/ProductController.java
create mode 100644 reactive-programming/src/main/java/org/mangmang/entity/Product.java
create mode 100644 reactive-programming/src/main/java/org/mangmang/repository/ProductRepository.java
create mode 100644 reactive-programming/src/main/java/org/mangmang/service/ProductService.java
create mode 100644 reactive-programming/src/main/resources/application.yml
create mode 100644 spring-cloud-demo/config-server/pom.xml
create mode 100644 spring-cloud-demo/config-server/src/main/java/com/mangmang/ConfigServerApplication.java
create mode 100644 spring-cloud-demo/config-server/src/main/resources/application.yml
create mode 100644 spring-cloud-demo/eureka-server/pom.xml
create mode 100644 spring-cloud-demo/eureka-server/src/main/java/com/mangmang/EurekaServerApplication.java
create mode 100644 spring-cloud-demo/eureka-server/src/main/resources/application.yml
create mode 100644 spring-cloud-demo/gateway-service/pom.xml
create mode 100644 spring-cloud-demo/gateway-service/src/main/java/com/mangmang/GatewayServiceApplication.java
create mode 100644 spring-cloud-demo/gateway-service/src/main/resources/application.yml
create mode 100644 spring-cloud-demo/gateway-service/src/main/resources/bootstrap.yml
create mode 100644 spring-cloud-demo/order-service/pom.xml
create mode 100644 spring-cloud-demo/order-service/src/main/java/com/mangmang/OrderServiceApplication.java
create mode 100644 spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/UserClient.java
create mode 100644 spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/Order.java
create mode 100644 spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/User.java
create mode 100644 spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/controller/OrderController.java
create mode 100644 spring-cloud-demo/order-service/src/main/resources/application.yml
create mode 100644 spring-cloud-demo/order-service/src/main/resources/bootstrap.yml
create mode 100644 spring-cloud-demo/pom.xml
create mode 100644 spring-cloud-demo/user-service/pom.xml
create mode 100644 spring-cloud-demo/user-service/src/main/java/com/mangmang/UserServiceApplication.java
create mode 100644 spring-cloud-demo/user-service/src/main/java/com/mangmang/controller/UserController.java
create mode 100644 spring-cloud-demo/user-service/src/main/java/com/mangmang/entity/User.java
create mode 100644 spring-cloud-demo/user-service/src/main/resources/application.yml
create mode 100644 spring-cloud-demo/user-service/src/main/resources/bootstrap.yml
create mode 100644 spring-data-jpa-read-write-separation/pom.xml
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/SpringDataJpaReadWriteSeparationApplication.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/DataSource.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/TargetDataSource.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceAspect.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceConfig.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DynamicDataSource.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/controller/UserController.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/entity/User.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/repository/UserRepository.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/service/UserService.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/java/com/mangmang/service/impl/UserServiceImpl.java
create mode 100644 spring-data-jpa-read-write-separation/src/main/resources/application.yml
create mode 100644 swing-and-javafx/pom.xml
create mode 100644 swing-and-javafx/src/main/java/com/mangmang/HelloWordSwing.java
create mode 100644 swing-and-javafx/src/main/java/com/mangmang/HelloWorldFX.java
create mode 100644 swing-and-javafx/src/main/java/com/mangmang/ImageConverterApp.java
create mode 100644 websocket/pom.xml
create mode 100644 websocket/src/main/java/com/mangmang/WebSocketDemoApplication.java
create mode 100644 websocket/src/main/java/com/mangmang/config/WebSocketConfig.java
create mode 100644 websocket/src/main/java/com/mangmang/controller/MessageController.java
create mode 100644 websocket/src/main/java/com/mangmang/listener/WebSocketEventListener.java
create mode 100644 websocket/src/main/java/com/mangmang/model/Message.java
create mode 100644 websocket/src/main/resources/application.yml
diff --git a/.gitignore b/.gitignore
index a1c2a23..c0d39de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,9 @@
*.zip
*.tar.gz
*.rar
+*.iml
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+.idea
+/.idea/
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 261eeb9..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..100bbba
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+
+ com.mangmang
+ learning-nexus
+ 1.0.0
+ pom
+ learning-nexus
+
+
+
+ reactive-programming
+ spring-data-jpa-read-write-separation
+ spring-cloud-demo
+ swing-and-javafx
+ websocket
+
+
+
+ 17
+ 2.6.7
+ 2021.0.2
+ ${java.version}
+ ${java.version}
+ UTF-8
+ 0.16.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+
+
+
diff --git a/reactive-programming/pom.xml b/reactive-programming/pom.xml
new file mode 100644
index 0000000..bad5628
--- /dev/null
+++ b/reactive-programming/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+
+ org.mangmang
+ reactive-programming
+ 1.0-SNAPSHOT
+ jar
+
+
+ com.mangmang
+ learning-nexus
+ 1.0.0
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.springframework.boot
+ spring-boot-starter-data-mongodb-reactive
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
\ No newline at end of file
diff --git a/reactive-programming/src/main/java/org/mangmang/ReactiveProgrammingApplication.java b/reactive-programming/src/main/java/org/mangmang/ReactiveProgrammingApplication.java
new file mode 100644
index 0000000..7289d0d
--- /dev/null
+++ b/reactive-programming/src/main/java/org/mangmang/ReactiveProgrammingApplication.java
@@ -0,0 +1,15 @@
+package org.mangmang;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Hello world!
+ *
+ */
+@SpringBootApplication
+public class ReactiveProgrammingApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ReactiveProgrammingApplication.class, args);
+ }
+}
diff --git a/reactive-programming/src/main/java/org/mangmang/controller/HelloController.java b/reactive-programming/src/main/java/org/mangmang/controller/HelloController.java
new file mode 100644
index 0000000..9fd6d20
--- /dev/null
+++ b/reactive-programming/src/main/java/org/mangmang/controller/HelloController.java
@@ -0,0 +1,12 @@
+package org.mangmang.controller;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class HelloController {
+ @GetMapping("/hello")
+ public String sayHello() {
+ return "Hello, Spring Boot!";
+ }
+}
diff --git a/reactive-programming/src/main/java/org/mangmang/controller/ProductController.java b/reactive-programming/src/main/java/org/mangmang/controller/ProductController.java
new file mode 100644
index 0000000..ca3b33d
--- /dev/null
+++ b/reactive-programming/src/main/java/org/mangmang/controller/ProductController.java
@@ -0,0 +1,74 @@
+package org.mangmang.controller;
+
+import org.mangmang.entity.Product;
+import org.mangmang.service.ProductService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+@RestController
+@RequestMapping("/products")
+public class ProductController {
+
+ private final ProductService productService;
+
+ @Autowired
+ public ProductController(ProductService productService) {
+ this.productService = productService;
+ }
+
+ @GetMapping
+ public Flux getAllProducts() {
+ return productService.getAllProducts();
+ }
+
+ @GetMapping("/{id}")
+ public Mono> getProductById(@PathVariable String id) {
+ return productService.getProductById(id)
+ .map(ResponseEntity::ok)
+ .defaultIfEmpty(ResponseEntity.notFound().build());
+ }
+
+ @GetMapping("/category/{category}")
+ public Flux getProductsByCategory(@PathVariable String category) {
+ return productService.getProductsByCategory(category);
+ }
+
+ @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+ public Flux streamAllProducts() {
+ return productService.getAllProducts();
+ }
+
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public Mono createProduct(@RequestBody Product product) {
+ return productService.saveProduct(product);
+ }
+
+ @PutMapping("/{id}")
+ public Mono> updateProduct(@PathVariable String id, @RequestBody Product product) {
+ return productService.getProductById(id)
+ .flatMap(existingProduct -> {
+ existingProduct.setName(product.getName());
+ existingProduct.setPrice(product.getPrice());
+ existingProduct.setCategory(product.getCategory());
+ return productService.saveProduct(existingProduct);
+ })
+ .map(updatedProduct -> ResponseEntity.ok(updatedProduct))
+ .defaultIfEmpty(ResponseEntity.notFound().build());
+ }
+
+ @DeleteMapping("/{id}")
+ public Mono> deleteProduct(@PathVariable String id) {
+ return productService.getProductById(id)
+ .flatMap(existingProduct ->
+ productService.deleteProduct(id)
+ .then(Mono.just(new ResponseEntity(HttpStatus.OK)))
+ )
+ .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
+ }
+}
diff --git a/reactive-programming/src/main/java/org/mangmang/entity/Product.java b/reactive-programming/src/main/java/org/mangmang/entity/Product.java
new file mode 100644
index 0000000..4f552db
--- /dev/null
+++ b/reactive-programming/src/main/java/org/mangmang/entity/Product.java
@@ -0,0 +1,15 @@
+package org.mangmang.entity;
+
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Data
+@Document
+public class Product {
+ @Id
+ private String id;
+ private String name;
+ private double price;
+ private String category;
+}
diff --git a/reactive-programming/src/main/java/org/mangmang/repository/ProductRepository.java b/reactive-programming/src/main/java/org/mangmang/repository/ProductRepository.java
new file mode 100644
index 0000000..16360df
--- /dev/null
+++ b/reactive-programming/src/main/java/org/mangmang/repository/ProductRepository.java
@@ -0,0 +1,9 @@
+package org.mangmang.repository;
+
+import org.mangmang.entity.Product;
+import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
+import reactor.core.publisher.Flux;
+
+public interface ProductRepository extends ReactiveMongoRepository {
+ Flux findByCategory(String category);
+}
diff --git a/reactive-programming/src/main/java/org/mangmang/service/ProductService.java b/reactive-programming/src/main/java/org/mangmang/service/ProductService.java
new file mode 100644
index 0000000..e17960d
--- /dev/null
+++ b/reactive-programming/src/main/java/org/mangmang/service/ProductService.java
@@ -0,0 +1,39 @@
+package org.mangmang.service;
+
+import org.mangmang.entity.Product;
+import org.mangmang.repository.ProductRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+@Service
+public class ProductService {
+
+ private final ProductRepository productRepository;
+
+ @Autowired
+ public ProductService(ProductRepository productRepository) {
+ this.productRepository = productRepository;
+ }
+
+ public Flux getAllProducts() {
+ return productRepository.findAll();
+ }
+
+ public Mono getProductById(String id) {
+ return productRepository.findById(id);
+ }
+
+ public Flux getProductsByCategory(String category) {
+ return productRepository.findByCategory(category);
+ }
+
+ public Mono saveProduct(Product product) {
+ return productRepository.save(product);
+ }
+
+ public Mono deleteProduct(String id) {
+ return productRepository.deleteById(id);
+ }
+}
diff --git a/reactive-programming/src/main/resources/application.yml b/reactive-programming/src/main/resources/application.yml
new file mode 100644
index 0000000..e69de29
diff --git a/spring-cloud-demo/config-server/pom.xml b/spring-cloud-demo/config-server/pom.xml
new file mode 100644
index 0000000..8225fe6
--- /dev/null
+++ b/spring-cloud-demo/config-server/pom.xml
@@ -0,0 +1,34 @@
+
+ 4.0.0
+
+ com.mangmang
+ spring-cloud-demo
+ 1.0.0
+
+
+
+ config-server
+ config-server
+ jar
+
+
+
+ org.springframework.cloud
+ spring-cloud-config-server
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-cloud-demo/config-server/src/main/java/com/mangmang/ConfigServerApplication.java b/spring-cloud-demo/config-server/src/main/java/com/mangmang/ConfigServerApplication.java
new file mode 100644
index 0000000..22d4161
--- /dev/null
+++ b/spring-cloud-demo/config-server/src/main/java/com/mangmang/ConfigServerApplication.java
@@ -0,0 +1,19 @@
+package com.mangmang;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.config.server.EnableConfigServer;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+
+/**
+ * 配置中心
+ * 功能:统一管理各服务的配置,支持从 Git 仓库中读取配置文件
+ */
+@SpringBootApplication
+@EnableConfigServer
+@EnableEurekaClient
+public class ConfigServerApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ConfigServerApplication.class, args);
+ }
+}
diff --git a/spring-cloud-demo/config-server/src/main/resources/application.yml b/spring-cloud-demo/config-server/src/main/resources/application.yml
new file mode 100644
index 0000000..95846fa
--- /dev/null
+++ b/spring-cloud-demo/config-server/src/main/resources/application.yml
@@ -0,0 +1,27 @@
+# 服务器配置
+server:
+ # 服务器端口号,设置为8888
+ port: 8888
+
+# Spring应用配置
+spring:
+ application:
+ # 应用名称,设置为config-server
+ name: config-server
+ cloud:
+ config:
+ server:
+ git:
+ # Git仓库的URI,用于存储配置文件
+ uri: https://github.com/liujing33/MangMang
+ # 默认的Git分支,设置为main
+ default-label: main
+ # 搜索路径,使用{application}作为占位符,表示根据应用名称查找配置文件
+ search-paths: /
+
+# Eureka客户端配置
+eureka:
+ client:
+ serviceUrl:
+ # Eureka服务器的默认区域URL,设置为本地8761端口
+ defaultZone: http://localhost:8761/eureka/
diff --git a/spring-cloud-demo/eureka-server/pom.xml b/spring-cloud-demo/eureka-server/pom.xml
new file mode 100644
index 0000000..a276d2c
--- /dev/null
+++ b/spring-cloud-demo/eureka-server/pom.xml
@@ -0,0 +1,33 @@
+
+ 4.0.0
+
+ com.mangmang
+ spring-cloud-demo
+ 1.0.0
+
+
+ eureka-server
+ jar
+ eureka-server
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-server
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-cloud-demo/eureka-server/src/main/java/com/mangmang/EurekaServerApplication.java b/spring-cloud-demo/eureka-server/src/main/java/com/mangmang/EurekaServerApplication.java
new file mode 100644
index 0000000..b76934b
--- /dev/null
+++ b/spring-cloud-demo/eureka-server/src/main/java/com/mangmang/EurekaServerApplication.java
@@ -0,0 +1,17 @@
+package com.mangmang;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
+
+/**
+ * 服务注册中心
+ * 功能:用于服务注册和发现,微服务启动时会向 Eureka 注册自己,并通过 Eureka 发现其他服务
+ */
+@SpringBootApplication
+@EnableEurekaServer
+public class EurekaServerApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(EurekaServerApplication.class, args);
+ }
+}
diff --git a/spring-cloud-demo/eureka-server/src/main/resources/application.yml b/spring-cloud-demo/eureka-server/src/main/resources/application.yml
new file mode 100644
index 0000000..85da4fa
--- /dev/null
+++ b/spring-cloud-demo/eureka-server/src/main/resources/application.yml
@@ -0,0 +1,21 @@
+# server: 配置服务器相关的参数
+server:
+ # port: 指定服务器监听的端口号,默认值为8761
+ port: 8761
+
+# spring: 配置Spring应用相关的参数
+spring:
+ application:
+ # name: 指定Spring应用的名称,这里设置为eureka-server
+ name: eureka-server
+
+# eureka: 配置Eureka服务器和客户端相关的参数
+eureka:
+ client:
+ # register-with-eureka: 是否将当前实例注册到Eureka服务器,false表示不注册
+ register-with-eureka: false
+ # fetch-registry: 是否从Eureka服务器获取注册表信息,false表示不获取
+ fetch-registry: false
+ server:
+ # wait-time-in-ms-when-sync-empty: 当同步空注册表时的等待时间(毫秒),0表示不等待
+ wait-time-in-ms-when-sync-empty: 0
diff --git a/spring-cloud-demo/gateway-service/pom.xml b/spring-cloud-demo/gateway-service/pom.xml
new file mode 100644
index 0000000..c827629
--- /dev/null
+++ b/spring-cloud-demo/gateway-service/pom.xml
@@ -0,0 +1,46 @@
+
+ 4.0.0
+
+ com.mangmang
+ spring-cloud-demo
+ 1.0.0
+
+
+ gateway-service
+ gateway-service
+ jar
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-cloud-demo/gateway-service/src/main/java/com/mangmang/GatewayServiceApplication.java b/spring-cloud-demo/gateway-service/src/main/java/com/mangmang/GatewayServiceApplication.java
new file mode 100644
index 0000000..510e2d9
--- /dev/null
+++ b/spring-cloud-demo/gateway-service/src/main/java/com/mangmang/GatewayServiceApplication.java
@@ -0,0 +1,17 @@
+package com.mangmang;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+
+/**
+ * Hello world!
+ *
+ */
+@SpringBootApplication
+@EnableEurekaClient
+public class GatewayServiceApplication {
+ public static void main( String[] args ) {
+ SpringApplication.run(GatewayServiceApplication.class, args);
+ }
+}
diff --git a/spring-cloud-demo/gateway-service/src/main/resources/application.yml b/spring-cloud-demo/gateway-service/src/main/resources/application.yml
new file mode 100644
index 0000000..97a6b83
--- /dev/null
+++ b/spring-cloud-demo/gateway-service/src/main/resources/application.yml
@@ -0,0 +1,49 @@
+# 服务器配置
+server:
+ # 服务器端口号,设置为8080
+ port: 8080
+
+# Eureka客户端配置
+eureka:
+ client:
+ serviceUrl:
+ # Eureka服务器的默认区域URL,指向本地8761端口的Eureka服务
+ defaultZone: http://localhost:8761/eureka/
+
+# Spring Cloud配置
+spring:
+ cloud:
+ gateway:
+ discovery:
+ locator:
+ # 启用服务发现定位器,允许通过服务名称进行路由
+ enabled: true
+ routes:
+ # 用户服务路由配置
+ - id: user-service
+ # 使用负载均衡方式指向user-service服务
+ uri: lb://user-service
+ predicates:
+ # 匹配路径为/api/users/**的请求
+ - Path=/api/users/**
+ filters:
+ # 去除路径中的第一个前缀
+ - StripPrefix=1
+ # 订单服务路由配置
+ - id: order-service
+ # 使用负载均衡方式指向order-service服务
+ uri: lb://order-service
+ predicates:
+ # 匹配路径为/api/orders/**的请求
+ - Path=/api/orders/**
+ filters:
+ # 去除路径中的第一个前缀
+ - StripPrefix=1
+
+# 管理端点配置
+management:
+ endpoints:
+ web:
+ exposure:
+ # 暴露所有管理端点
+ include: "*"
diff --git a/spring-cloud-demo/gateway-service/src/main/resources/bootstrap.yml b/spring-cloud-demo/gateway-service/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..198cf97
--- /dev/null
+++ b/spring-cloud-demo/gateway-service/src/main/resources/bootstrap.yml
@@ -0,0 +1,18 @@
+# Spring 应用程序配置
+spring:
+ # 应用程序相关配置
+ application:
+ # 应用程序名称,用于标识当前服务
+ name: gateway-service
+ # Spring Cloud 相关配置
+ cloud:
+ # 配置中心相关配置
+ config:
+ # 配置中心服务发现相关配置
+ discovery:
+ # 是否启用配置中心服务发现,true 表示启用
+ enabled: true
+ # 配置中心服务的服务ID,用于服务发现
+ service-id: config-server
+ # 是否在配置中心不可用时快速失败,true 表示快速失败
+ fail-fast: true
diff --git a/spring-cloud-demo/order-service/pom.xml b/spring-cloud-demo/order-service/pom.xml
new file mode 100644
index 0000000..59dc54e
--- /dev/null
+++ b/spring-cloud-demo/order-service/pom.xml
@@ -0,0 +1,55 @@
+
+ 4.0.0
+
+ com.mangmang
+ spring-cloud-demo
+ 1.0.0
+
+
+ order-service
+ order-service
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-cloud-demo/order-service/src/main/java/com/mangmang/OrderServiceApplication.java b/spring-cloud-demo/order-service/src/main/java/com/mangmang/OrderServiceApplication.java
new file mode 100644
index 0000000..35a0995
--- /dev/null
+++ b/spring-cloud-demo/order-service/src/main/java/com/mangmang/OrderServiceApplication.java
@@ -0,0 +1,16 @@
+package com.mangmang;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+
+@SpringBootApplication
+@EnableEurekaClient
+@EnableFeignClients
+public class OrderServiceApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(OrderServiceApplication.class, args);
+ }
+}
diff --git a/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/UserClient.java b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/UserClient.java
new file mode 100644
index 0000000..031f0fe
--- /dev/null
+++ b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/UserClient.java
@@ -0,0 +1,13 @@
+package com.mangmang.orderservice.client;
+
+import com.mangmang.orderservice.client.model.User;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+@FeignClient(name = "user-service")
+public interface UserClient {
+
+ @GetMapping("/users/{id}")
+ User getUserById(@PathVariable("id") Long id);
+}
diff --git a/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/Order.java b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/Order.java
new file mode 100644
index 0000000..32d5043
--- /dev/null
+++ b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/Order.java
@@ -0,0 +1,15 @@
+package com.mangmang.orderservice.client.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class Order {
+ private Long id;
+ private Long userId;
+ private String productName;
+ private Double price;
+}
diff --git a/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/User.java b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/User.java
new file mode 100644
index 0000000..28b7b75
--- /dev/null
+++ b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/client/model/User.java
@@ -0,0 +1,10 @@
+package com.mangmang.orderservice.client.model;
+
+import lombok.Data;
+
+@Data
+public class User {
+ private Long id;
+ private String name;
+ private String email;
+}
diff --git a/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/controller/OrderController.java b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/controller/OrderController.java
new file mode 100644
index 0000000..6abbf53
--- /dev/null
+++ b/spring-cloud-demo/order-service/src/main/java/com/mangmang/orderservice/controller/OrderController.java
@@ -0,0 +1,65 @@
+package com.mangmang.orderservice.controller;
+
+import com.mangmang.orderservice.client.UserClient;
+import com.mangmang.orderservice.client.model.Order;
+import com.mangmang.orderservice.client.model.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/orders")
+public class OrderController {
+
+ @Value("${server.port}")
+ private String port;
+
+ @Autowired
+ private UserClient userClient;
+
+ private List orders = new ArrayList<>();
+
+ public OrderController() {
+ orders.add(new Order(1L, 1L, "iPhone 13", 5999.99));
+ orders.add(new Order(2L, 1L, "MacBook Pro", 12999.99));
+ orders.add(new Order(3L, 2L, "iPad Pro", 4999.99));
+ }
+
+ @GetMapping
+ public List getAllOrders() {
+ return orders;
+ }
+
+ @GetMapping("/{id}")
+ public Order getOrderById(@PathVariable Long id) {
+ return orders.stream()
+ .filter(order -> order.getId().equals(id))
+ .findFirst()
+ .orElseThrow(() -> new RuntimeException("Order not found"));
+ }
+
+ @GetMapping("/user/{userId}")
+ public List getOrdersByUserId(@PathVariable Long userId) {
+ // 验证用户是否存在
+ User user = userClient.getUserById(userId);
+ if (user == null) {
+ throw new RuntimeException("User not found");
+ }
+
+ return orders.stream()
+ .filter(order -> order.getUserId().equals(userId))
+ .collect(Collectors.toList());
+ }
+
+ @GetMapping("/port")
+ public String getPort() {
+ return "Order service running on port: " + port;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-demo/order-service/src/main/resources/application.yml b/spring-cloud-demo/order-service/src/main/resources/application.yml
new file mode 100644
index 0000000..d312ab3
--- /dev/null
+++ b/spring-cloud-demo/order-service/src/main/resources/application.yml
@@ -0,0 +1,19 @@
+# server配置块,用于定义服务器相关的配置
+server:
+ # 服务器端口号,指定应用程序监听的端口
+ port: 8082
+
+# eureka配置块,用于定义Eureka客户端相关的配置
+eureka:
+ client:
+ serviceUrl:
+ # Eureka服务器的默认区域URL,指定Eureka服务器的地址
+ defaultZone: http://localhost:8761/eureka/
+
+# management配置块,用于定义管理端点相关的配置
+management:
+ endpoints:
+ web:
+ exposure:
+ # 暴露所有管理端点,允许通过Web访问所有管理端点
+ include: "*"
diff --git a/spring-cloud-demo/order-service/src/main/resources/bootstrap.yml b/spring-cloud-demo/order-service/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..899d581
--- /dev/null
+++ b/spring-cloud-demo/order-service/src/main/resources/bootstrap.yml
@@ -0,0 +1,18 @@
+# Spring 应用程序配置
+spring:
+ # 应用程序相关配置
+ application:
+ # 应用程序名称,用于标识当前服务
+ name: order-service
+ # Spring Cloud 相关配置
+ cloud:
+ # Spring Cloud Config 配置
+ config:
+ # 配置服务发现相关设置
+ discovery:
+ # 启用配置服务发现,允许通过服务发现机制查找配置服务器
+ enabled: true
+ # 配置服务器的服务ID,用于在服务注册中心查找配置服务器
+ service-id: config-server
+ # 配置客户端在启动时快速失败,如果无法连接到配置服务器,则应用程序将无法启动
+ fail-fast: true
diff --git a/spring-cloud-demo/pom.xml b/spring-cloud-demo/pom.xml
new file mode 100644
index 0000000..f249b3b
--- /dev/null
+++ b/spring-cloud-demo/pom.xml
@@ -0,0 +1,34 @@
+
+ 4.0.0
+
+
+ com.mangmang
+ learning-nexus
+ 1.0.0
+
+
+
+ spring-cloud-demo
+ spring-cloud-demo
+ pom
+
+
+ eureka-server
+ config-server
+ user-service
+ order-service
+ gateway-service
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
diff --git a/spring-cloud-demo/user-service/pom.xml b/spring-cloud-demo/user-service/pom.xml
new file mode 100644
index 0000000..d16f128
--- /dev/null
+++ b/spring-cloud-demo/user-service/pom.xml
@@ -0,0 +1,53 @@
+
+ 4.0.0
+
+ com.mangmang
+ spring-cloud-demo
+ 1.0.0
+
+
+
+ user-service
+ user-service
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-config
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/spring-cloud-demo/user-service/src/main/java/com/mangmang/UserServiceApplication.java b/spring-cloud-demo/user-service/src/main/java/com/mangmang/UserServiceApplication.java
new file mode 100644
index 0000000..05ad540
--- /dev/null
+++ b/spring-cloud-demo/user-service/src/main/java/com/mangmang/UserServiceApplication.java
@@ -0,0 +1,16 @@
+package com.mangmang;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+
+/**
+ * 用户服务
+ */
+@SpringBootApplication
+@EnableEurekaClient
+public class UserServiceApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(UserServiceApplication.class, args);
+ }
+}
diff --git a/spring-cloud-demo/user-service/src/main/java/com/mangmang/controller/UserController.java b/spring-cloud-demo/user-service/src/main/java/com/mangmang/controller/UserController.java
new file mode 100644
index 0000000..662928c
--- /dev/null
+++ b/spring-cloud-demo/user-service/src/main/java/com/mangmang/controller/UserController.java
@@ -0,0 +1,43 @@
+package com.mangmang.controller;
+
+import com.mangmang.entity.User;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RestController
+@RequestMapping("/users")
+public class UserController {
+
+ @Value("${server.port}")
+ private String port;
+
+ private final List users = Arrays.asList(
+ new User(1L, "张三", "zhangsan@example.com"),
+ new User(2L, "李四", "lisi@example.com"),
+ new User(3L, "王五", "wangwu@example.com")
+ );
+
+ @GetMapping
+ public List getAllUsers() {
+ return users;
+ }
+
+ @GetMapping("/{id}")
+ public User getUserById(@PathVariable Long id) {
+ return users.stream()
+ .filter(user -> user.getId().equals(id))
+ .findFirst()
+ .orElseThrow(() -> new RuntimeException("User not found"));
+ }
+
+ @GetMapping("/port")
+ public String getPort() {
+ return "User service running on port: " + port;
+ }
+}
diff --git a/spring-cloud-demo/user-service/src/main/java/com/mangmang/entity/User.java b/spring-cloud-demo/user-service/src/main/java/com/mangmang/entity/User.java
new file mode 100644
index 0000000..51d680c
--- /dev/null
+++ b/spring-cloud-demo/user-service/src/main/java/com/mangmang/entity/User.java
@@ -0,0 +1,14 @@
+package com.mangmang.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class User {
+ private Long id;
+ private String name;
+ private String email;
+}
diff --git a/spring-cloud-demo/user-service/src/main/resources/application.yml b/spring-cloud-demo/user-service/src/main/resources/application.yml
new file mode 100644
index 0000000..04d0bbf
--- /dev/null
+++ b/spring-cloud-demo/user-service/src/main/resources/application.yml
@@ -0,0 +1,19 @@
+# server: 配置服务器相关的设置
+server:
+ # port: 指定服务器监听的端口号,默认为8081
+ port: 8081
+
+# eureka: 配置Eureka客户端相关的设置
+eureka:
+ client:
+ serviceUrl:
+ # defaultZone: 指定Eureka服务器的默认注册地址,默认为http://localhost:8761/eureka/
+ defaultZone: http://localhost:8761/eureka/
+
+# management: 配置Spring Boot Actuator相关的设置
+management:
+ endpoints:
+ web:
+ exposure:
+ # include: 指定暴露的Actuator端点,*表示暴露所有端点
+ include: "*"
diff --git a/spring-cloud-demo/user-service/src/main/resources/bootstrap.yml b/spring-cloud-demo/user-service/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..bd34625
--- /dev/null
+++ b/spring-cloud-demo/user-service/src/main/resources/bootstrap.yml
@@ -0,0 +1,19 @@
+# Spring 应用配置
+spring:
+ # 应用名称配置
+ application:
+ # 设置应用的名称为 user-service
+ name: user-service
+ # Spring Cloud 配置
+ cloud:
+ config:
+ # 配置服务发现相关设置
+ discovery:
+ # 启用配置服务发现功能
+ enabled: true
+ # 指定配置服务的服务ID为 config-server
+ service-id: config-server
+ # 启用快速失败机制,当配置服务不可用时,应用将快速失败而不是等待
+ fail-fast: true
+
+
diff --git a/spring-data-jpa-read-write-separation/pom.xml b/spring-data-jpa-read-write-separation/pom.xml
new file mode 100644
index 0000000..b69aa5a
--- /dev/null
+++ b/spring-data-jpa-read-write-separation/pom.xml
@@ -0,0 +1,41 @@
+
+ 4.0.0
+
+
+ com.mangmang
+ learning-nexus
+ 1.0.0
+
+
+ spring-data-jpa-read-write-separation
+ jar
+
+
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ mysql
+ mysql-connector-java
+
+
+
diff --git a/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/SpringDataJpaReadWriteSeparationApplication.java b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/SpringDataJpaReadWriteSeparationApplication.java
new file mode 100644
index 0000000..ba0cd87
--- /dev/null
+++ b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/SpringDataJpaReadWriteSeparationApplication.java
@@ -0,0 +1,12 @@
+package com.mangmang;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class SpringDataJpaReadWriteSeparationApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(SpringDataJpaReadWriteSeparationApplication.class, args);
+ }
+}
diff --git a/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/DataSource.java b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/DataSource.java
new file mode 100644
index 0000000..4b3e44e
--- /dev/null
+++ b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/DataSource.java
@@ -0,0 +1,5 @@
+package com.mangmang.annotaion;
+
+public enum DataSource {
+ MASTER, SLAVE;
+}
diff --git a/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/TargetDataSource.java b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/TargetDataSource.java
new file mode 100644
index 0000000..fc82f66
--- /dev/null
+++ b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/annotaion/TargetDataSource.java
@@ -0,0 +1,24 @@
+package com.mangmang.annotaion;
+
+
+import java.lang.annotation.*;
+
+/**
+ * 数据源切换注解,用于在方法或类级别指定使用的数据源
+ * 该注解可应用于类或方法上,运行时生效,并会保留在javadoc文档中
+ * @see DataSource 数据源类型枚举,包含可用数据源定义(如MASTER主库、SLAVE从库等)
+ * 参数说明:
+ * @value 指定目标数据源名称,默认使用MASTER主库数据源
+ * 通过该参数实现数据源动态切换,需配合AOP或拦截器实现具体切换逻辑
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface TargetDataSource {
+ /**
+ * 数据源类型配置参数
+ * @return 数据源枚举值,默认返回主库数据源标识
+ */
+ DataSource value() default DataSource.MASTER;
+}
+
diff --git a/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceAspect.java b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceAspect.java
new file mode 100644
index 0000000..9da66b9
--- /dev/null
+++ b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceAspect.java
@@ -0,0 +1,79 @@
+package com.mangmang.config;
+
+import com.mangmang.annotaion.DataSource;
+import com.mangmang.annotaion.TargetDataSource;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+
+
+/**
+ * 动态数据源切面类,用于实现基于注解的数据源动态切换功能
+ *
+ * 本切面通过拦截带有@TargetDataSource注解的方法,在执行目标方法前切换数据源,
+ * 执行完成后自动清理数据源上下文,实现主从库的动态路由
+ */
+@Slf4j
+@Order(1)
+@Aspect
+@Component
+public class DataSourceAspect {
+
+ /**
+ * 定义切点:拦截所有标注@TargetDataSource注解的方法
+ *
+ * @Pointcut 使用注解表达式定位需要拦截的方法,注解全路径为com.mangmang.annotaion.TargetDataSource
+ */
+ @Pointcut("@annotation(com.mangmang.annotaion.TargetDataSource)")
+ public void dataSourcePointcut() {
+
+ }
+
+ /**
+ * 环绕通知方法,实现数据源的动态切换和清理
+ *
+ * @param point 连接点对象,提供被拦截方法的相关信息
+ * @return Object 目标方法的执行结果
+ * @throws Throwable 目标方法可能抛出的异常
+ *
+ * 执行流程:
+ * 1. 获取方法签名和注解信息
+ * 2. 根据注解值设置数据源(无注解时默认主库)
+ * 3. 执行目标方法
+ * 4. 清理线程数据源上下文
+ */
+ @Around("dataSourcePointcut()")
+ public Object around(ProceedingJoinPoint point) throws Throwable {
+ // 获取方法元数据
+ MethodSignature signature = (MethodSignature) point.getSignature();
+ Method method = signature.getMethod();
+
+ // 解析目标数据源注解
+ TargetDataSource ds = method.getAnnotation(TargetDataSource.class);
+
+ // 设置数据源策略:有注解使用注解值,无注解使用默认主库
+ if (ds == null) {
+ DynamicDataSource.DynamicDataSourceContextHolder.setDataSource(DataSource.MASTER.name());
+ log.info("使用主库");
+ } else {
+ DynamicDataSource.DynamicDataSourceContextHolder.setDataSource(ds.value().name());
+ }
+
+ try {
+ // 执行被拦截的目标方法
+ return point.proceed();
+ } finally {
+ // 确保线程数据源上下文清理,避免内存泄漏
+ DynamicDataSource.DynamicDataSourceContextHolder.clearDataSource();
+ log.info("清除数据源");
+ }
+ }
+}
+
diff --git a/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceConfig.java b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceConfig.java
new file mode 100644
index 0000000..9f1ac8b
--- /dev/null
+++ b/spring-data-jpa-read-write-separation/src/main/java/com/mangmang/config/DataSourceConfig.java
@@ -0,0 +1,75 @@
+package com.mangmang.config;
+
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 数据源配置类,用于配置主从数据源和动态路由数据源
+ */
+@Configuration
+public class DataSourceConfig {
+
+ /**
+ * 创建主数据源Bean
+ * @return 配置好的主数据源实例,自动绑定spring.datasource.master前缀的配置属性
+ */
+ @Bean
+ @ConfigurationProperties(prefix = "spring.datasource.master")
+ public DataSource masterDataSource() {
+ return DataSourceBuilder.create().build();
+ }
+
+ /**
+ * 创建从数据源Bean
+ * @return 配置好的从数据源实例,自动绑定spring.datasource.slave前缀的配置属性
+ */
+ @Bean
+ @ConfigurationProperties(prefix = "spring.datasource.slave")
+ public DataSource slaveDataSource() {
+ return DataSourceBuilder.create().build();
+ }
+
+ /**
+ * 创建动态数据源路由(主数据源作为默认数据源)
+ * @param masterDataSource 通过@Qualifier注入的主数据源实例
+ * @param slaveDataSource 通过@Qualifier注入的从数据源实例
+ * @return 配置好的动态数据源路由实例
+ */
+ @Bean
+ @Primary
+ public DynamicDataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
+ @Qualifier("slaveDataSource") DataSource slaveDataSource) {
+ DynamicDataSource dynamicDataSource = new DynamicDataSource();
+ // 构建数据源映射表
+ Map