diff --git a/bus/README.md b/bus/README.md new file mode 100644 index 0000000..1069585 --- /dev/null +++ b/bus/README.md @@ -0,0 +1,6 @@ +# TwoStepsFromJava-Cloud-Bus + +Spring Cloud 示例项目:Bus + + +Spring Cloud Release Trains: [Dalston.SR1](http://projects.spring.io/spring-cloud/) \ No newline at end of file diff --git a/bus/mall-web/pom.xml b/bus/mall-web/pom.xml new file mode 100755 index 0000000..6476c20 --- /dev/null +++ b/bus/mall-web/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + mall-web + MS Blog Projects(Bus): Mall Web + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.cloud + spring-cloud-starter-ribbon + + + org.springframework.cloud + spring-cloud-starter-feign + + + org.springframework.cloud + spring-cloud-starter-hystrix + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.cloud + spring-cloud-starter-bus-kafka + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/Application.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/Application.java new file mode 100644 index 0000000..386b272 --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/Application.java @@ -0,0 +1,39 @@ +/*** + * 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 io.twostepsfromjava.cloud; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.feign.EnableFeignClients; + +/** + * TwoStepsFromJava Cloud -- Mall Web Project + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableFeignClients +@EnableDiscoveryClient +@RemoteApplicationEventScan +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java new file mode 100644 index 0000000..597ed94 --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java @@ -0,0 +1,71 @@ +/* + * 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 io.twostepsfromjava.cloud.bus; + + +import com.google.common.base.MoreObjects; +import org.springframework.cloud.bus.event.RemoteApplicationEvent; + +/** + * 商品事件 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductEvent extends RemoteApplicationEvent { + /** 消息类型:更新商品,值为: {@value} */ + public static final String ET_UPDATE = "update"; + /** 消息类型:删除商品,值为: {@value} */ + public static final String ET_DELETE = "delete"; + + // ======================================================================== + // fields ================================================================= + private String action; + private String itemCode; + + // ======================================================================== + // constructor ============================================================ + public ProductEvent() { + super(); + } + + public ProductEvent(Object source, String originService, String destinationService, String action, String itemCode) { + super(source, originService, destinationService); + this.action = action; + this.itemCode = itemCode; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("itemCode", this.getItemCode()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } +} diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java new file mode 100644 index 0000000..ed312d5 --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java @@ -0,0 +1,48 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.controller; + +import io.twostepsfromjava.cloud.web.mall.dto.ProductDto; +import io.twostepsfromjava.cloud.web.mall.service.ProductService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + + +/** + * Product Controller + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/products") +public class ProductController { + @Autowired + private ProductService productService; + + @RequestMapping(method = RequestMethod.GET) + public List list() { + return this.productService.findAll(); + } + + @RequestMapping(value = "/{itemCode}", method = RequestMethod.GET) + public ProductDto detail(@PathVariable String itemCode) { + return this.productService.loadByItemCode(itemCode); + } +} diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/dto/ProductDto.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/dto/ProductDto.java new file mode 100644 index 0000000..d3da9c9 --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/dto/ProductDto.java @@ -0,0 +1,84 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.dto; + +import com.google.common.base.MoreObjects; + +/** + * 商品信息DTO对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class ProductDto { + private static final long serialVersionUID = 1L; + + // ======================================================================== + // fields ================================================================= + private String itemCode; // 商品货号 + private String name; // 商品名称 + private String bandName; // 商品品牌名称 + private int price; // 商品价格(分) + + // ======================================================================== + // constructor ============================================================ + public ProductDto() { + } + + public ProductDto(String itemCode, String name, String bandName, int price) { + this.itemCode = itemCode; + this.name = name; + this.bandName = bandName; + this.price = price; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("itemCode", this.getItemCode()) + .add("name", this.getName()) + .add("bandName", this.getBandName()) + .add("price", this.getPrice()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getBandName() { + return bandName; + } + public void setBandName(String bandName) { + this.bandName = bandName; + } + + public int getPrice() { + return price; + } + public void setPrice(int price) { + this.price = price; + } +} diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsg.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsg.java new file mode 100644 index 0000000..51303a1 --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsg.java @@ -0,0 +1,67 @@ +/* + * 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 io.twostepsfromjava.cloud.web.mall.mq; + + +import com.google.common.base.MoreObjects; + +/** + * 商品消息 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductMsg { + /** 消息类型:更新商品,值为: {@value} */ + public static final String MA_UPDATE = "update"; + /** 消息类型:删除商品,值为: {@value} */ + public static final String MA_DELETE = "delete"; + + // ======================================================================== + // fields ================================================================= + private String action; + private String itemCode; + + // ======================================================================== + // constructor ============================================================ + public ProductMsg() { } + + public ProductMsg(String action, String itemCode) { + this.action = action; + this.itemCode = itemCode; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("itemCode", this.getItemCode()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } +} diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsgListener.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsgListener.java new file mode 100644 index 0000000..0539db5 --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsgListener.java @@ -0,0 +1,51 @@ +/* + * 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 io.twostepsfromjava.cloud.web.mall.mq; + + +import io.twostepsfromjava.cloud.web.mall.dto.ProductDto; +import io.twostepsfromjava.cloud.web.mall.service.ProductService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + + +/** + * 商品消息监听器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductMsgListener { + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + protected ProductService productService; + + public void onProductMsgSink(ProductMsg productMsg) { + if (ProductMsg.MA_UPDATE.equalsIgnoreCase(productMsg.getAction())) { + this.logger.debug("收到商品变更消息,商品货号: {}", productMsg.getItemCode()); + // 重新获取该商品信息 + ProductDto productDto = this.productService.loadByItemCode(productMsg.getItemCode()); + if (null != productDto) + this.logger.debug("重新获取到的商品信息为:{}", productDto); + else + this.logger.debug("货号为:{} 的商品不存在", productMsg.getItemCode()); + } else if (ProductMsg.MA_DELETE.equalsIgnoreCase(productMsg.getAction())) { + this.logger.debug("收到商品删除消息,所要删除商品货号为: {}", productMsg.getItemCode()); + } else { + this.logger.debug("收到未知商品消息: {}", productMsg); + } + } +} diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductEventListener.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductEventListener.java new file mode 100644 index 0000000..cf54729 --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductEventListener.java @@ -0,0 +1,54 @@ +/* + * 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 io.twostepsfromjava.cloud.web.mall.service; + +import io.twostepsfromjava.cloud.bus.ProductEvent; +import io.twostepsfromjava.cloud.web.mall.dto.ProductDto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + + +/** + * 远程事件监听 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@Component +public class ProductEventListener implements ApplicationListener { + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + protected ProductService productService; + + @Override + public void onApplicationEvent(ProductEvent productEvent) { + if (ProductEvent.ET_UPDATE.equalsIgnoreCase(productEvent.getAction())) { + this.logger.debug("Web微服务收到商品变更事件,商品货号: {}", productEvent.getItemCode()); + // 重新获取该商品信息 + ProductDto productDto = this.productService.loadByItemCode(productEvent.getItemCode()); + if (null != productDto) + this.logger.debug("重新获取到的商品信息为:{}", productDto); + else + this.logger.debug("货号为:{} 的商品不存在", productEvent.getItemCode()); + } else if (ProductEvent.ET_DELETE.equalsIgnoreCase(productEvent.getAction())) { + this.logger.debug("Web微服务收到商品删除事件,所要删除商品货号为: {}", productEvent.getItemCode()); + } else { + this.logger.debug("Web微服务收到未知商品事件: {}", productEvent); + } + } +} diff --git a/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java new file mode 100644 index 0000000..b0c769a --- /dev/null +++ b/bus/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java @@ -0,0 +1,38 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + +import io.twostepsfromjava.cloud.web.mall.dto.ProductDto; +import org.springframework.cloud.netflix.feign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import java.util.List; + + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@FeignClient("productservice") +public interface ProductService { + @RequestMapping(value = "/products", method = RequestMethod.GET) + List findAll(); + + @RequestMapping(value = "/products/{itemCode}", method = RequestMethod.GET) + ProductDto loadByItemCode(@PathVariable("itemCode") String itemCode); +} diff --git a/bus/mall-web/src/main/resources/application.properties b/bus/mall-web/src/main/resources/application.properties new file mode 100644 index 0000000..3594b0a --- /dev/null +++ b/bus/mall-web/src/main/resources/application.properties @@ -0,0 +1,15 @@ +server.port=8080 + +spring.application.name=MALL-WEB + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO +logging.level.io.twostepsfromjava=DEBUG + +# ===================================================================================================================== +# == stream / kafka == +# ===================================================================================================================== +spring.cloud.stream.kafka.binder.brokers=localhost +spring.cloud.stream.kafka.binder.defaultBrokerPort=9092 +spring.cloud.stream.kafka.binder.zkNodes=localhost \ No newline at end of file diff --git a/bus/mall-web/src/main/resources/banner.txt b/bus/mall-web/src/main/resources/banner.txt new file mode 100644 index 0000000..2d4682f --- /dev/null +++ b/bus/mall-web/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Consumer == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/bus/parent/pom.xml b/bus/parent/pom.xml new file mode 100644 index 0000000..c6f3dbd --- /dev/null +++ b/bus/parent/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + MS Blog Projects(Bus): Parent Pom + pom + + + UTF-8 + + + + + + org.springframework.cloud + spring-cloud-dependencies + Dalston.SR3 + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/bus/pom.xml b/bus/pom.xml new file mode 100755 index 0000000..63a0cb0 --- /dev/null +++ b/bus/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + parent + + + twostepsfromjava-clouds + 1.0.0-SNAPSHOT + MS Blog Projects -- Bus + pom + + + parent + service-discovery + + product-service + user-service + + mall-web + + diff --git a/bus/product-service/pom.xml b/bus/product-service/pom.xml new file mode 100755 index 0000000..b011225 --- /dev/null +++ b/bus/product-service/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + product-service + MS Blog Projects(Bus): Product Service Server + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.cloud + spring-cloud-starter-bus-kafka + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/Application.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/Application.java new file mode 100644 index 0000000..e6bd5ee --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/Application.java @@ -0,0 +1,37 @@ +/*** + * 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 io.twostepsfromjava.cloud; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * TwoStepsFromJava Cloud -- ProductDto Service 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableDiscoveryClient +@RemoteApplicationEventScan +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java new file mode 100644 index 0000000..597ed94 --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java @@ -0,0 +1,71 @@ +/* + * 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 io.twostepsfromjava.cloud.bus; + + +import com.google.common.base.MoreObjects; +import org.springframework.cloud.bus.event.RemoteApplicationEvent; + +/** + * 商品事件 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductEvent extends RemoteApplicationEvent { + /** 消息类型:更新商品,值为: {@value} */ + public static final String ET_UPDATE = "update"; + /** 消息类型:删除商品,值为: {@value} */ + public static final String ET_DELETE = "delete"; + + // ======================================================================== + // fields ================================================================= + private String action; + private String itemCode; + + // ======================================================================== + // constructor ============================================================ + public ProductEvent() { + super(); + } + + public ProductEvent(Object source, String originService, String destinationService, String action, String itemCode) { + super(source, originService, destinationService); + this.action = action; + this.itemCode = itemCode; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("itemCode", this.getItemCode()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/api/ProductEndpoint.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/api/ProductEndpoint.java new file mode 100644 index 0000000..be39d8d --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/api/ProductEndpoint.java @@ -0,0 +1,59 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.api; + +import io.twostepsfromjava.cloud.product.dto.ProductDto; +import io.twostepsfromjava.cloud.product.service.ProductService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * ProductDto API服务 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/products") +public class ProductEndpoint { + protected Logger logger = LoggerFactory.getLogger(ProductEndpoint.class); + + @Autowired + ProductService productService; + + @RequestMapping(method = RequestMethod.GET) + public List list() { + return this.productService.findAll(); + } + + @RequestMapping(value = "/{itemCode}", method = RequestMethod.GET) + public ProductDto detail(@PathVariable String itemCode) { + return this.productService.findOne(itemCode); + } + + // FIXME: 该端点仅仅是用来测试消息发送,并不包含任何业务逻辑处理 + @RequestMapping(value = "/{itemCode}", method = RequestMethod.POST) + public ProductDto save(@PathVariable String itemCode) { + ProductDto productDto = this.productService.findOne(itemCode); + if (null != productDto) { + this.productService.save(productDto); + } + return productDto; + } +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/dto/ProductDto.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/dto/ProductDto.java new file mode 100644 index 0000000..500fe43 --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/dto/ProductDto.java @@ -0,0 +1,84 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.dto; + +import com.google.common.base.MoreObjects; + +/** + * 商品信息DTO对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class ProductDto { + private static final long serialVersionUID = 1L; + + // ======================================================================== + // fields ================================================================= + private String itemCode; // 商品货号 + private String name; // 商品名称 + private String bandName; // 商品品牌名称 + private int price; // 商品价格(分) + + // ======================================================================== + // constructor ============================================================ + public ProductDto() { + } + + public ProductDto(String itemCode, String name, String bandName, int price) { + this.itemCode = itemCode; + this.name = name; + this.bandName = bandName; + this.price = price; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("itemCode", this.getItemCode()) + .add("name", this.getName()) + .add("bandName", this.getBandName()) + .add("price", this.getPrice()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getBandName() { + return bandName; + } + public void setBandName(String bandName) { + this.bandName = bandName; + } + + public int getPrice() { + return price; + } + public void setPrice(int price) { + this.price = price; + } +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/entity/Product.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/entity/Product.java new file mode 100644 index 0000000..ca56fce --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/entity/Product.java @@ -0,0 +1,84 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.entity; + +import com.google.common.base.MoreObjects; + +/** + * 商品信息实体对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class Product { + private static final long serialVersionUID = 1L; + + // ======================================================================== + // fields ================================================================= + private String itemCode; // 商品货号 + private String name; // 商品名称 + private String bandName; // 商品品牌名称 + private int price; // 商品价格(分) + + // ======================================================================== + // constructor ============================================================ + public Product() { + } + + public Product(String itemCode, String name, String bandName, int price) { + this.itemCode = itemCode; + this.name = name; + this.bandName = bandName; + this.price = price; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("itemCode", this.getItemCode()) + .add("name", this.getName()) + .add("bandName", this.getBandName()) + .add("price", this.getPrice()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getBandName() { + return bandName; + } + public void setBandName(String bandName) { + this.bandName = bandName; + } + + public int getPrice() { + return price; + } + public void setPrice(int price) { + this.price = price; + } +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/mq/ProductMsg.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/mq/ProductMsg.java new file mode 100644 index 0000000..4d18bf7 --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/mq/ProductMsg.java @@ -0,0 +1,67 @@ +/* + * 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 io.twostepsfromjava.cloud.product.mq; + + +import com.google.common.base.MoreObjects; + +/** + * 商品消息 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductMsg { + /** 消息类型:更新商品,值为: {@value} */ + public static final String MA_UPDATE = "update"; + /** 消息类型:删除商品,值为: {@value} */ + public static final String MA_DELETE = "delete"; + + // ======================================================================== + // fields ================================================================= + private String action; + private String itemCode; + + // ======================================================================== + // constructor ============================================================ + public ProductMsg() { } + + public ProductMsg(String action, String itemCode) { + this.action = action; + this.itemCode = itemCode; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("itemCode", this.getItemCode()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/service/ProductService.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/service/ProductService.java new file mode 100644 index 0000000..462fd53 --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/service/ProductService.java @@ -0,0 +1,119 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.service; + +import io.twostepsfromjava.cloud.bus.ProductEvent; +import io.twostepsfromjava.cloud.product.dto.ProductDto; +import io.twostepsfromjava.cloud.product.mq.ProductMsg; +import io.twostepsfromjava.cloud.product.util.ApplicationContextHolder; +import io.twostepsfromjava.cloud.product.util.RemoteApplicationEventPublisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + + +/** + * 商品服务 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@Service +public class ProductService { + protected Logger logger = LoggerFactory.getLogger(ProductService.class); + + private List productList; + + @Autowired + public ProductService() { + this.productList = this.buildProducts(); + } + + /** + * 获取商品列表 + * @return + */ + public List findAll() { + return this.productList; + } + + /** + * 根据ItemCode获取 + * @param itemCode + * @return + */ + public ProductDto findOne(String itemCode) { + for (ProductDto productDto : this.productList) { + if (productDto.getItemCode().equalsIgnoreCase(itemCode)) + return productDto; + } + + return null; + } + + /** + * 保存或更新商品信息 + * @param productDto + * @return + */ + public ProductDto save(ProductDto productDto) { + // TODO: 实现商品保存处理 + for (ProductDto sourceProductDto : this.productList) { + if (sourceProductDto.getItemCode().equalsIgnoreCase(productDto.getItemCode())) { + sourceProductDto.setName(sourceProductDto.getName() + "-new"); + sourceProductDto.setPrice(sourceProductDto.getPrice() + 100); + productDto = sourceProductDto; + break; + } + } + + // 发送商品消息 + // this.sendMsg(ProductMsg.MA_UPDATE, productDto.getItemCode()); + this.fireEvent(ProductEvent.ET_UPDATE, productDto); + + return productDto; + } + + protected void sendMsg(String msgAction, String itemCode) { + ProductMsg productMsg = new ProductMsg(msgAction, itemCode); + this.logger.debug("发送商品消息:{} ", productMsg); + + // 发送消息 + // this.source.output().send(MessageBuilder.withPayload(productMsg).build()); + } + + protected void fireEvent(String eventAction, ProductDto productDto) { + ProductEvent productEvent = new ProductEvent(productDto, + ApplicationContextHolder.getApplicationContext().getId(), "*:**", + eventAction, productDto.getItemCode()); + + // 发布事件 + RemoteApplicationEventPublisher.publishEvent(productEvent); + } + + protected List buildProducts() { + List products = new ArrayList<>(); + products.add(new ProductDto("item-1", "测试商品-1", "TwoStepsFromJava", 100)); + products.add(new ProductDto("item-2", "测试商品-2", "TwoStepsFromJava", 200)); + products.add(new ProductDto("item-3", "测试商品-3", "TwoStepsFromJava", 300)); + products.add(new ProductDto("item-4", "测试商品-4", "TwoStepsFromJava", 400)); + products.add(new ProductDto("item-5", "测试商品-5", "TwoStepsFromJava", 500)); + products.add(new ProductDto("item-6", "测试商品-6", "TwoStepsFromJava", 600)); + return products; + } +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/util/ApplicationContextHolder.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/util/ApplicationContextHolder.java new file mode 100755 index 0000000..0c96b70 --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/util/ApplicationContextHolder.java @@ -0,0 +1,74 @@ +/* + * 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 io.twostepsfromjava.cloud.product.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +/** + * ApplicationContext辅助类 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@Component +public class ApplicationContextHolder implements ApplicationContextAware, DisposableBean { + private static Logger logger = LoggerFactory.getLogger(ApplicationContextHolder.class); + private static ApplicationContext applicationContext = null; + + @Override + public void destroy() throws Exception { + ApplicationContextHolder.clearHolder(); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + logger.debug("注入ApplicationContext到SpringContextHolder: {}", applicationContext); + + if (ApplicationContextHolder.applicationContext != null) { + logger.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为: {}", ApplicationContextHolder.applicationContext); + } + + ApplicationContextHolder.applicationContext = applicationContext; + } + + /** + * 取得存储在静态变量中的ApplicationContext. + */ + public static ApplicationContext getApplicationContext() { + assertContextInjected(); + return applicationContext; + } + + /** + * 清除SpringContextHolder中的ApplicationContext为Null. + */ + public static void clearHolder() { + logger.debug("清除SpringContextHolder中的ApplicationContext: {}", applicationContext); + applicationContext = null; + } + + /** + * 检查ApplicationContext不为空. + */ + private static void assertContextInjected() { + Assert.notNull(applicationContext, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder."); + } +} diff --git a/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/util/RemoteApplicationEventPublisher.java b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/util/RemoteApplicationEventPublisher.java new file mode 100755 index 0000000..b0dfecb --- /dev/null +++ b/bus/product-service/src/main/java/io/twostepsfromjava/cloud/product/util/RemoteApplicationEventPublisher.java @@ -0,0 +1,44 @@ +/** + * 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 io.twostepsfromjava.cloud.product.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.bus.event.RemoteApplicationEvent; +import org.springframework.context.ApplicationContext; + + +/** + * 远程事件发布者 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class RemoteApplicationEventPublisher { + protected static Logger logger = LoggerFactory.getLogger(RemoteApplicationEventPublisher.class); + + /** + * 发布一个事件 + * @param event + */ + public static void publishEvent(RemoteApplicationEvent event){ + ApplicationContext context = ApplicationContextHolder.getApplicationContext(); + if(null != context) { + context.publishEvent(event); + logger.debug("已发布事件:{}", event); + }else{ + logger.warn("无法获取到当前Spring上下文信息,不能够发布事件"); + } + } +} \ No newline at end of file diff --git a/bus/product-service/src/main/resources/application.properties b/bus/product-service/src/main/resources/application.properties new file mode 100644 index 0000000..4860fdb --- /dev/null +++ b/bus/product-service/src/main/resources/application.properties @@ -0,0 +1,15 @@ +server.port=2100 + +spring.application.name=productservice + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO +logging.level.io.twostepsfromjava=DEBUG + +# ===================================================================================================================== +# == stream / kafka == +# ===================================================================================================================== +spring.cloud.stream.kafka.binder.brokers=localhost +spring.cloud.stream.kafka.binder.defaultBrokerPort=9092 +spring.cloud.stream.kafka.binder.zkNodes=localhost \ No newline at end of file diff --git a/bus/product-service/src/main/resources/banner.txt b/bus/product-service/src/main/resources/banner.txt new file mode 100644 index 0000000..a692d74 --- /dev/null +++ b/bus/product-service/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Product == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/bus/service-discovery/pom.xml b/bus/service-discovery/pom.xml new file mode 100755 index 0000000..5d93b2c --- /dev/null +++ b/bus/service-discovery/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + service-discovery + MS Blog Projects(Bus): Eureka Server + + + + org.springframework.cloud + spring-cloud-starter-eureka-server + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/bus/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java b/bus/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java new file mode 100644 index 0000000..31a533d --- /dev/null +++ b/bus/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java @@ -0,0 +1,35 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.discovery; + + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +/** + * TwoStepsFromJava Cloud -- Service Discoery 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableEurekaServer +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} diff --git a/bus/service-discovery/src/main/resources/application.properties b/bus/service-discovery/src/main/resources/application.properties new file mode 100644 index 0000000..269e732 --- /dev/null +++ b/bus/service-discovery/src/main/resources/application.properties @@ -0,0 +1,8 @@ +server.port=8260 + +eureka.instance.hostname=localhost +eureka.client.register-with-eureka=false +eureka.client.fetch-registry=false +eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/bus/service-discovery/src/main/resources/banner.txt b/bus/service-discovery/src/main/resources/banner.txt new file mode 100644 index 0000000..e12a88a --- /dev/null +++ b/bus/service-discovery/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Discovery == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/bus/user-service/pom.xml b/bus/user-service/pom.xml new file mode 100755 index 0000000..3e73894 --- /dev/null +++ b/bus/user-service/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + user-service + MS Blog Projects(Bus): User Service Server + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.cloud + spring-cloud-starter-bus-kafka + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/Application.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/Application.java new file mode 100644 index 0000000..0635930 --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/Application.java @@ -0,0 +1,37 @@ +/*** + * 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 io.twostepsfromjava.cloud; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * TwoStepsFromJava Cloud -- User Service 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableDiscoveryClient +@RemoteApplicationEventScan +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java new file mode 100644 index 0000000..597ed94 --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/bus/ProductEvent.java @@ -0,0 +1,71 @@ +/* + * 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 io.twostepsfromjava.cloud.bus; + + +import com.google.common.base.MoreObjects; +import org.springframework.cloud.bus.event.RemoteApplicationEvent; + +/** + * 商品事件 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductEvent extends RemoteApplicationEvent { + /** 消息类型:更新商品,值为: {@value} */ + public static final String ET_UPDATE = "update"; + /** 消息类型:删除商品,值为: {@value} */ + public static final String ET_DELETE = "delete"; + + // ======================================================================== + // fields ================================================================= + private String action; + private String itemCode; + + // ======================================================================== + // constructor ============================================================ + public ProductEvent() { + super(); + } + + public ProductEvent(Object source, String originService, String destinationService, String action, String itemCode) { + super(source, originService, destinationService); + this.action = action; + this.itemCode = itemCode; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("itemCode", this.getItemCode()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } +} diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/event/UserEvent.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/event/UserEvent.java new file mode 100644 index 0000000..a92d676 --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/event/UserEvent.java @@ -0,0 +1,93 @@ +/* + * 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 io.twostepsfromjava.cloud.event; + + +import com.google.common.base.MoreObjects; +import io.twostepsfromjava.cloud.user.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; + +/** + * 用户事件 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class UserEvent extends ApplicationEvent { + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + /** 消息类型:更新用户,值为: {@value} */ + public static final String ET_UPDATE = "update"; + + // ======================================================================== + // fields ================================================================= + private String action; + private User user; + + // ======================================================================== + // constructor ============================================================ + public UserEvent(User user) { + super(user); + this.user = user; + } + + public UserEvent(User user, String action) { + super(user); + this.action = action; + this.user = user; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("user", this.getUser()).toString(); + } + + /** + * 发布事件 + */ + public void fire() { + ApplicationContext context = ApplicationContextHolder.getApplicationContext(); + if(null != context) { + logger.debug("发布事件:{}", this); + context.publishEvent(this); + }else{ + logger.warn("无法获取到当前Spring上下文信息,不能够发布事件"); + } + } + + public void foo() { + new UserEvent(user, UserEvent.ET_UPDATE).fire(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public User getUser() { + return user; + } + public void setUser(User user) { + this.user = user; + } +} diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/event/UserEventListener.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/event/UserEventListener.java new file mode 100644 index 0000000..04d67ef --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/event/UserEventListener.java @@ -0,0 +1,37 @@ +/* + * 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 io.twostepsfromjava.cloud.event; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +/** + * 用户事件监听 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@Component +public class UserEventListener implements ApplicationListener { + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void onApplicationEvent(UserEvent userEvent) { + this.logger.debug("收到用户事件:{} ", userEvent); + // TODO: 实现具体的业务处理 + } +} diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/User.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/User.java new file mode 100644 index 0000000..3de27a2 --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/User.java @@ -0,0 +1,83 @@ +/*** + * 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 io.twostepsfromjava.cloud.user; + +import com.google.common.base.MoreObjects; + +/** + * 用户信息DTO对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class User { + private static final long serialVersionUID = 1L; + // ======================================================================== + // fields ================================================================= + private String loginName; // 用户登陆名称 + private String name; // 用户姓名 + private String avatar; // 用户头像 + private String memos; // 信息备注 + + // ======================================================================== + // constructor ============================================================ + public User() { + } + + public User(String loginName, String name, String avatar, String memos) { + this.loginName = loginName; + this.name = name; + this.avatar = avatar; + this.memos = memos; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("loginName", this.getLoginName()) + .add("name", this.getName()) + .add("avatar", this.getAvatar()) + .add("memos", this.getMemos()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getLoginName() { + return loginName; + } + public void setLoginName(String loginName) { + this.loginName = loginName; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getAvatar() { + return avatar; + } + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getMemos() { + return memos; + } + public void setMemos(String memos) { + this.memos = memos; + } +} diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/api/UserEndpoint.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/api/UserEndpoint.java new file mode 100644 index 0000000..77d3e08 --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/api/UserEndpoint.java @@ -0,0 +1,42 @@ +/*** + * 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 io.twostepsfromjava.cloud.user.api; + +import io.twostepsfromjava.cloud.user.dto.UserDto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + + +/** + * User API服务 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/users") +public class UserEndpoint { + protected Logger logger = LoggerFactory.getLogger(UserEndpoint.class); + + @Value("${server.port:2200}") + private int serverPort = 2200; + + @RequestMapping(value = "/{loginName}", method = RequestMethod.GET) + public UserDto detail(@PathVariable String loginName) { + String memos = "I come form " + this.serverPort; + return new UserDto(loginName, loginName, "/avatar/default.png", memos); + } +} diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/dto/UserDto.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/dto/UserDto.java new file mode 100644 index 0000000..5ca1eef --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/dto/UserDto.java @@ -0,0 +1,83 @@ +/*** + * 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 io.twostepsfromjava.cloud.user.dto; + +import com.google.common.base.MoreObjects; + +/** + * 用户信息DTO对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class UserDto { + private static final long serialVersionUID = 1L; + // ======================================================================== + // fields ================================================================= + private String loginName; // 用户登陆名称 + private String name; // 用户姓名 + private String avatar; // 用户头像 + private String memos; // 信息备注 + + // ======================================================================== + // constructor ============================================================ + public UserDto() { + } + + public UserDto(String loginName, String name, String avatar, String memos) { + this.loginName = loginName; + this.name = name; + this.avatar = avatar; + this.memos = memos; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("loginName", this.getLoginName()) + .add("name", this.getName()) + .add("avatar", this.getAvatar()) + .add("memos", this.getMemos()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getLoginName() { + return loginName; + } + public void setLoginName(String loginName) { + this.loginName = loginName; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getAvatar() { + return avatar; + } + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getMemos() { + return memos; + } + public void setMemos(String memos) { + this.memos = memos; + } +} diff --git a/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/service/ProductEventListener.java b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/service/ProductEventListener.java new file mode 100644 index 0000000..4a5a448 --- /dev/null +++ b/bus/user-service/src/main/java/io/twostepsfromjava/cloud/user/service/ProductEventListener.java @@ -0,0 +1,43 @@ +/* + * 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 io.twostepsfromjava.cloud.user.service; + +import io.twostepsfromjava.cloud.bus.ProductEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + + +/** + * 远程事件监听 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@Component +public class ProductEventListener implements ApplicationListener { + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void onApplicationEvent(ProductEvent productEvent) { + if (ProductEvent.ET_UPDATE.equalsIgnoreCase(productEvent.getAction())) { + this.logger.debug("用户微服务收到商品变更事件,商品货号: {}", productEvent.getItemCode()); + } else if (ProductEvent.ET_DELETE.equalsIgnoreCase(productEvent.getAction())) { + this.logger.debug("用户微服务收到商品删除事件,所要删除商品货号为: {}", productEvent.getItemCode()); + } else { + this.logger.debug("用户微服务收到未知商品事件: {}", productEvent); + } + } +} diff --git a/bus/user-service/src/main/resources/application.properties b/bus/user-service/src/main/resources/application.properties new file mode 100644 index 0000000..ee041f0 --- /dev/null +++ b/bus/user-service/src/main/resources/application.properties @@ -0,0 +1,15 @@ +server.port=2200 + +spring.application.name=USER-SERVICE + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO +logging.level.io.twostepsfromjava=DEBUG + +# ===================================================================================================================== +# == stream / kafka == +# ===================================================================================================================== +spring.cloud.stream.kafka.binder.brokers=localhost +spring.cloud.stream.kafka.binder.defaultBrokerPort=9092 +spring.cloud.stream.kafka.binder.zkNodes=localhost \ No newline at end of file diff --git a/bus/user-service/src/main/resources/banner.txt b/bus/user-service/src/main/resources/banner.txt new file mode 100644 index 0000000..6d6d6bb --- /dev/null +++ b/bus/user-service/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- User == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..bbf8a8b --- /dev/null +++ b/config/README.md @@ -0,0 +1,6 @@ +# TwoStepsFromJava-Cloud-Feign + +Spring Cloud 示例项目:结合Ribbon和Feign实现声明式服务调用。 + + +Spring Cloud Release Trains: [Dalston.SR1](http://projects.spring.io/spring-cloud/) \ No newline at end of file diff --git a/config/config-client/pom.xml b/config/config-client/pom.xml new file mode 100755 index 0000000..2e0a237 --- /dev/null +++ b/config/config-client/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + config-client + Spring Cloud Sample Projects: Config Client + + + + org.springframework.cloud + spring-cloud-starter-config + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + \ No newline at end of file diff --git a/config/config-client/src/main/java/io/twostepsfromjava/cloud/web/mall/Application.java b/config/config-client/src/main/java/io/twostepsfromjava/cloud/web/mall/Application.java new file mode 100644 index 0000000..916fd94 --- /dev/null +++ b/config/config-client/src/main/java/io/twostepsfromjava/cloud/web/mall/Application.java @@ -0,0 +1,36 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.feign.EnableFeignClients; + +/** + * TwoStepsFromJava Cloud -- Config Client Project + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableDiscoveryClient +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/config/config-client/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ConfigController.java b/config/config-client/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ConfigController.java new file mode 100644 index 0000000..c417c5b --- /dev/null +++ b/config/config-client/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ConfigController.java @@ -0,0 +1,40 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.controller; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +/** + * Config Client Test Controller + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/cfg") +public class ConfigController { + @Value("${foo}") + String foo; + + @Value("${bar}") + String bar; + + @RequestMapping(value = "/foo") + public String foo(){ + return foo + "——" + bar; + } +} diff --git a/config/config-client/src/main/resources/application.properties b/config/config-client/src/main/resources/application.properties new file mode 100644 index 0000000..1303c65 --- /dev/null +++ b/config/config-client/src/main/resources/application.properties @@ -0,0 +1,3 @@ +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/config/config-client/src/main/resources/banner.txt b/config/config-client/src/main/resources/banner.txt new file mode 100644 index 0000000..8860e63 --- /dev/null +++ b/config/config-client/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- config client == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/config/config-client/src/main/resources/bootstrap.properties b/config/config-client/src/main/resources/bootstrap.properties new file mode 100644 index 0000000..331a4e1 --- /dev/null +++ b/config/config-client/src/main/resources/bootstrap.properties @@ -0,0 +1,5 @@ +server.port=8080 + +spring.application.name=mallWeb +spring.cloud.config.profile=dev +spring.cloud.config.uri= http://localhost:8280/ diff --git a/config/config-client/src/main/resources/logback.xml b/config/config-client/src/main/resources/logback.xml new file mode 100644 index 0000000..d4b7206 --- /dev/null +++ b/config/config-client/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + + + logs/log-%d{yyyy-MM-dd}.%i.log + + + 64 MB + + + + + + DEBUG + + + true + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + DEBUG + + + + + + + + + diff --git a/config/config-server/pom.xml b/config/config-server/pom.xml new file mode 100755 index 0000000..dcf6dd6 --- /dev/null +++ b/config/config-server/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + config-server + Spring Cloud Sample Projects: Config Server + + + + org.springframework.cloud + spring-cloud-config-server + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.cloud + spring-cloud-starter-eureka + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/config/config-server/src/main/java/io/twostepsfromjava/cloud/service/hello/Application.java b/config/config-server/src/main/java/io/twostepsfromjava/cloud/service/hello/Application.java new file mode 100644 index 0000000..87b9e88 --- /dev/null +++ b/config/config-server/src/main/java/io/twostepsfromjava/cloud/service/hello/Application.java @@ -0,0 +1,37 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.hello; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.config.server.EnableConfigServer; + +/** + * TwoStepsFromJava Cloud -- Config Server + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@SpringBootApplication +@EnableConfigServer +@EnableDiscoveryClient +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/config/config-server/src/main/resources/application.properties b/config/config-server/src/main/resources/application.properties new file mode 100644 index 0000000..ad4e4cc --- /dev/null +++ b/config/config-server/src/main/resources/application.properties @@ -0,0 +1,12 @@ +server.port=8280 + +spring.application.name=config-server + +spring.cloud.config.server.git.uri=https://github.com/cd826/SpringcloudSamplesConfig +spring.cloud.config.server.git.username=yourname +spring.cloud.config.server.git.password=yourpass +spring.cloud.config.server.git.basedir=tmp/ + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/config/config-server/src/main/resources/banner.txt b/config/config-server/src/main/resources/banner.txt new file mode 100644 index 0000000..123d812 --- /dev/null +++ b/config/config-server/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Config Server == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/config/config-server/src/main/resources/logback.xml b/config/config-server/src/main/resources/logback.xml new file mode 100644 index 0000000..d4b7206 --- /dev/null +++ b/config/config-server/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + + + logs/log-%d{yyyy-MM-dd}.%i.log + + + 64 MB + + + + + + DEBUG + + + true + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + DEBUG + + + + + + + + + diff --git a/config/parent/pom.xml b/config/parent/pom.xml new file mode 100644 index 0000000..84914e0 --- /dev/null +++ b/config/parent/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + Spring Cloud Sample Projects: Parent Pom + pom + + + UTF-8 + + + + + + org.springframework.cloud + spring-cloud-dependencies + Dalston.SR1 + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/config/pom.xml b/config/pom.xml new file mode 100755 index 0000000..fd13027 --- /dev/null +++ b/config/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + parent + + + twostepsfromjava-clouds + 1.0.0-SNAPSHOT + Spring Cloud Sample Projects + pom + + + parent + service-discovery + + config-server + config-client + + diff --git a/config/service-discovery/pom.xml b/config/service-discovery/pom.xml new file mode 100755 index 0000000..c7040cc --- /dev/null +++ b/config/service-discovery/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + service-discovery + Spring Cloud Sample Projects: Eureka Server + + + + org.springframework.cloud + spring-cloud-starter-eureka-server + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/config/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java b/config/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java new file mode 100644 index 0000000..31a533d --- /dev/null +++ b/config/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java @@ -0,0 +1,35 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.discovery; + + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +/** + * TwoStepsFromJava Cloud -- Service Discoery 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableEurekaServer +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} diff --git a/config/service-discovery/src/main/resources/application.properties b/config/service-discovery/src/main/resources/application.properties new file mode 100644 index 0000000..269e732 --- /dev/null +++ b/config/service-discovery/src/main/resources/application.properties @@ -0,0 +1,8 @@ +server.port=8260 + +eureka.instance.hostname=localhost +eureka.client.register-with-eureka=false +eureka.client.fetch-registry=false +eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/config/service-discovery/src/main/resources/banner.txt b/config/service-discovery/src/main/resources/banner.txt new file mode 100644 index 0000000..e12a88a --- /dev/null +++ b/config/service-discovery/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Discovery == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/config/service-discovery/src/main/resources/logback.xml b/config/service-discovery/src/main/resources/logback.xml new file mode 100644 index 0000000..d4b7206 --- /dev/null +++ b/config/service-discovery/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + + + logs/log-%d{yyyy-MM-dd}.%i.log + + + 64 MB + + + + + + DEBUG + + + true + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + DEBUG + + + + + + + + + diff --git a/eureka/service-discovery/pom.xml b/eureka/service-discovery/pom.xml index 3f7810a..bd7dbc0 100755 --- a/eureka/service-discovery/pom.xml +++ b/eureka/service-discovery/pom.xml @@ -18,6 +18,11 @@ org.springframework.cloud spring-cloud-starter-eureka-server + + + org.springframework.boot + spring-boot-starter-security + diff --git a/feign/mall-web/pom.xml b/feign/mall-web/pom.xml index 52b0350..deaee9c 100755 --- a/feign/mall-web/pom.xml +++ b/feign/mall-web/pom.xml @@ -37,5 +37,14 @@ product-service-api ${project.version} - + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + \ No newline at end of file diff --git a/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java b/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java index e9d33a5..9e6f229 100644 --- a/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java +++ b/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java @@ -42,8 +42,15 @@ public List list() { return this.productService.findAll(); } - @RequestMapping(value = "/{itemCode}", method = RequestMethod.GET) + @RequestMapping(value = "/{itemCode}", method = RequestMethod.POST) public Product detail(@PathVariable String itemCode) { + System.out.println("dddddddddd"); + return this.productService.loadByItemCodeEx(itemCode, "OBgEDj", "restore"); + } + + @RequestMapping(value = "/t/{itemCode}", method = RequestMethod.POST) + public Product detailEx(@PathVariable String itemCode) { + System.out.println("dddddddddd"); return this.productService.loadByItemCode(itemCode); } } diff --git a/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java b/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java index 805d4fa..95c5843 100644 --- a/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java +++ b/feign/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import java.util.List; @@ -37,4 +38,8 @@ public interface ProductService { @RequestMapping(value = "/products/{itemCode}", method = RequestMethod.GET) Product loadByItemCode(@PathVariable("itemCode") String itemCode); + @RequestMapping(value = "/products/{itemCode}/instruction/execute", method = RequestMethod.POST) + Product loadByItemCodeEx(@PathVariable("itemCode") String itemCode, + @RequestParam("user_id") String userId, + @RequestParam("instruction_code") String instructionCode); } diff --git a/feign/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/api/ProductEndpoint.java b/feign/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/api/ProductEndpoint.java index b5da7c5..df3f690 100644 --- a/feign/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/api/ProductEndpoint.java +++ b/feign/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/api/ProductEndpoint.java @@ -48,6 +48,19 @@ public Product detail(@PathVariable String itemCode) { return null; } + @RequestMapping(value = "/item/{itemCode}/instruction/execute", method = RequestMethod.POST) + public Product detailEx(@PathVariable String itemCode, + @RequestParam(value = "user_id", required = false) String userId, + @RequestParam(value = "instruction_code") String instructionCode) { + System.out.println("userId = " + userId); + List products = this.buildProducts(); + for (Product product : products) { + if (product.getItemCode().equalsIgnoreCase(itemCode)) + return product; + } + return null; + } + protected List buildProducts() { List products = new ArrayList<>(); products.add(new Product("item-1", "测试商品-1", "TwoStepsFromJava", 100)); diff --git a/hystrix-2/README.md b/hystrix-2/README.md new file mode 100644 index 0000000..bbf8a8b --- /dev/null +++ b/hystrix-2/README.md @@ -0,0 +1,6 @@ +# TwoStepsFromJava-Cloud-Feign + +Spring Cloud 示例项目:结合Ribbon和Feign实现声明式服务调用。 + + +Spring Cloud Release Trains: [Dalston.SR1](http://projects.spring.io/spring-cloud/) \ No newline at end of file diff --git a/hystrix-2/mall-web/pom.xml b/hystrix-2/mall-web/pom.xml new file mode 100755 index 0000000..9e97fd5 --- /dev/null +++ b/hystrix-2/mall-web/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + mall-web + Spring Cloud Sample Projects: Mall + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.cloud + spring-cloud-starter-ribbon + + + org.springframework.cloud + spring-cloud-starter-hystrix + + + org.springframework.cloud + spring-cloud-starter-hystrix-dashboard + + + org.springframework.boot + spring-boot-starter-actuator + + + + ${project.groupId} + product-service-api + ${project.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/Application.java b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/Application.java new file mode 100644 index 0000000..b7f8524 --- /dev/null +++ b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/Application.java @@ -0,0 +1,49 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.netflix.feign.EnableFeignClients; +import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +/** + * TwoStepsFromJava Cloud -- Mall Web Project + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableHystrixDashboard +@EnableCircuitBreaker +@EnableDiscoveryClient +@SpringBootApplication +public class Application { + + @Bean + @LoadBalanced + RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java new file mode 100644 index 0000000..e9d33a5 --- /dev/null +++ b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java @@ -0,0 +1,49 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.controller; + +import io.twostepsfromjava.cloud.product.dto.Product; +import io.twostepsfromjava.cloud.web.mall.service.ProductService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + + +/** + * Product Controller + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/products") +public class ProductController { + @Autowired + private ProductService productService; + + @RequestMapping(method = RequestMethod.GET) + public List list() { + return this.productService.findAll(); + } + + @RequestMapping(value = "/{itemCode}", method = RequestMethod.GET) + public Product detail(@PathVariable String itemCode) { + return this.productService.loadByItemCode(itemCode); + } +} diff --git a/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java new file mode 100644 index 0000000..4ddda9e --- /dev/null +++ b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java @@ -0,0 +1,37 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + +import io.twostepsfromjava.cloud.product.dto.Product; +import org.springframework.cloud.netflix.feign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import java.util.List; + + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public interface ProductService { + + List findAll(); + + Product loadByItemCode(String itemCode); + +} diff --git a/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/impl/ProductServiceImpl.java b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/impl/ProductServiceImpl.java new file mode 100644 index 0000000..b254d16 --- /dev/null +++ b/hystrix-2/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/impl/ProductServiceImpl.java @@ -0,0 +1,59 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service.impl; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import io.twostepsfromjava.cloud.product.dto.Product; +import io.twostepsfromjava.cloud.web.mall.service.ProductService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@Service +public class ProductServiceImpl implements ProductService { + @Autowired + private RestTemplate restTemplate; + + @Override + @HystrixCommand(fallbackMethod = "findAllFallback") + public List findAll() { + return this.restTemplate.getForEntity("http://PRODUCT-SERVICE/products", List.class).getBody(); + } + + @Override + public Product loadByItemCode(String itemCode) { + return this.restTemplate.getForEntity("http://PRODUCT-SERVICE/products/" + itemCode, Product.class).getBody(); + } + + public List findAllFallback() { + List products = new ArrayList<>(); + products.add(new Product("Failure-1", "固定商品-1", "Hystrix-Fallback", 100)); + products.add(new Product("Failure-2", "固定商品-2", "Hystrix-Fallback", 100)); + products.add(new Product("Failure-3", "固定商品-3", "Hystrix-Fallback", 100)); + products.add(new Product("Failure-4", "固定商品-4", "Hystrix-Fallback", 100)); + products.add(new Product("Failure-5", "固定商品-5", "Hystrix-Fallback", 100)); + products.add(new Product("Failure-6", "固定商品-6", "Hystrix-Fallback", 100)); + return products; + } +} diff --git a/hystrix-2/mall-web/src/main/resources/application.properties b/hystrix-2/mall-web/src/main/resources/application.properties new file mode 100644 index 0000000..e0a190b --- /dev/null +++ b/hystrix-2/mall-web/src/main/resources/application.properties @@ -0,0 +1,9 @@ +server.port=8080 + +spring.application.name=MALL-WEB + +feign.hystrix.enabled=true + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/hystrix-2/mall-web/src/main/resources/banner.txt b/hystrix-2/mall-web/src/main/resources/banner.txt new file mode 100644 index 0000000..2d4682f --- /dev/null +++ b/hystrix-2/mall-web/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Consumer == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/hystrix-2/mall-web/src/main/resources/logback.xml b/hystrix-2/mall-web/src/main/resources/logback.xml new file mode 100644 index 0000000..d4b7206 --- /dev/null +++ b/hystrix-2/mall-web/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + + + logs/log-%d{yyyy-MM-dd}.%i.log + + + 64 MB + + + + + + DEBUG + + + true + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + DEBUG + + + + + + + + + diff --git a/hystrix-2/parent/pom.xml b/hystrix-2/parent/pom.xml new file mode 100644 index 0000000..84914e0 --- /dev/null +++ b/hystrix-2/parent/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + Spring Cloud Sample Projects: Parent Pom + pom + + + UTF-8 + + + + + + org.springframework.cloud + spring-cloud-dependencies + Dalston.SR1 + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/hystrix-2/pom.xml b/hystrix-2/pom.xml new file mode 100755 index 0000000..4b24942 --- /dev/null +++ b/hystrix-2/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + parent + + + twostepsfromjava-clouds + 1.0.0-SNAPSHOT + Spring Cloud Sample Projects + pom + + + parent + service-discovery + + product-service-api + product-service + + mall-web + + turbine-server + + diff --git a/hystrix-2/product-service-api/pom.xml b/hystrix-2/product-service-api/pom.xml new file mode 100755 index 0000000..8c8f494 --- /dev/null +++ b/hystrix-2/product-service-api/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + product-service-api + Spring Cloud Sample Projects: Product Service API + \ No newline at end of file diff --git a/feign/product-service-api/src/main/java/io/twostepsfromjava/cloud/product/dto/Product.java b/hystrix-2/product-service-api/src/main/java/io/twostepsfromjava/cloud/product/dto/Product.java similarity index 100% rename from feign/product-service-api/src/main/java/io/twostepsfromjava/cloud/product/dto/Product.java rename to hystrix-2/product-service-api/src/main/java/io/twostepsfromjava/cloud/product/dto/Product.java diff --git a/hystrix-2/product-service/pom.xml b/hystrix-2/product-service/pom.xml new file mode 100755 index 0000000..ad6aaf9 --- /dev/null +++ b/hystrix-2/product-service/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + product-service + Spring Cloud Sample Projects: Product Service Server + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + + ${project.groupId} + product-service-api + ${project.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/hystrix-2/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/Application.java b/hystrix-2/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/Application.java new file mode 100644 index 0000000..fd2772f --- /dev/null +++ b/hystrix-2/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/Application.java @@ -0,0 +1,35 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.hello; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * TwoStepsFromJava Cloud -- Product Service 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableDiscoveryClient +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/hystrix-2/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/api/ProductEndpoint.java b/hystrix-2/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/api/ProductEndpoint.java new file mode 100644 index 0000000..37667be --- /dev/null +++ b/hystrix-2/product-service/src/main/java/io/twostepsfromjava/cloud/service/hello/api/ProductEndpoint.java @@ -0,0 +1,70 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.hello.api; + +import io.twostepsfromjava.cloud.product.dto.Product; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + + +/** + * Product API服务 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/products") +public class ProductEndpoint { + protected Logger logger = LoggerFactory.getLogger(ProductEndpoint.class); + + @RequestMapping(method = RequestMethod.GET) + public List list() { + try { + int sleepTime = new Random().nextInt(3000); + this.logger.debug("sleep time = {}ms", sleepTime); + Thread.sleep(sleepTime); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + return this.buildProducts(); + } + + @RequestMapping(value = "/{itemCode}", method = RequestMethod.GET) + public Product detail(@PathVariable String itemCode) { + List products = this.buildProducts(); + for (Product product : products) { + if (product.getItemCode().equalsIgnoreCase(itemCode)) + return product; + } + return null; + } + + protected List buildProducts() { + List products = new ArrayList<>(); + products.add(new Product("item-1", "测试商品-1", "TwoStepsFromJava", 100)); + products.add(new Product("item-2", "测试商品-2", "TwoStepsFromJava", 200)); + products.add(new Product("item-3", "测试商品-3", "TwoStepsFromJava", 300)); + products.add(new Product("item-4", "测试商品-4", "TwoStepsFromJava", 400)); + products.add(new Product("item-5", "测试商品-5", "TwoStepsFromJava", 500)); + products.add(new Product("item-6", "测试商品-6", "TwoStepsFromJava", 600)); + return products; + } +} diff --git a/hystrix-2/product-service/src/main/resources/application.properties b/hystrix-2/product-service/src/main/resources/application.properties new file mode 100644 index 0000000..1d1bf34 --- /dev/null +++ b/hystrix-2/product-service/src/main/resources/application.properties @@ -0,0 +1,7 @@ +server.port=2100 + +spring.application.name=PRODUCT-SERVICE + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/hystrix-2/product-service/src/main/resources/banner.txt b/hystrix-2/product-service/src/main/resources/banner.txt new file mode 100644 index 0000000..a692d74 --- /dev/null +++ b/hystrix-2/product-service/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Product == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/hystrix-2/product-service/src/main/resources/logback.xml b/hystrix-2/product-service/src/main/resources/logback.xml new file mode 100644 index 0000000..d4b7206 --- /dev/null +++ b/hystrix-2/product-service/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + + + logs/log-%d{yyyy-MM-dd}.%i.log + + + 64 MB + + + + + + DEBUG + + + true + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + DEBUG + + + + + + + + + diff --git a/hystrix-2/service-discovery/pom.xml b/hystrix-2/service-discovery/pom.xml new file mode 100755 index 0000000..c7040cc --- /dev/null +++ b/hystrix-2/service-discovery/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + service-discovery + Spring Cloud Sample Projects: Eureka Server + + + + org.springframework.cloud + spring-cloud-starter-eureka-server + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/hystrix-2/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java b/hystrix-2/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java new file mode 100644 index 0000000..31a533d --- /dev/null +++ b/hystrix-2/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java @@ -0,0 +1,35 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.discovery; + + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +/** + * TwoStepsFromJava Cloud -- Service Discoery 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableEurekaServer +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} diff --git a/hystrix-2/service-discovery/src/main/resources/application.properties b/hystrix-2/service-discovery/src/main/resources/application.properties new file mode 100644 index 0000000..269e732 --- /dev/null +++ b/hystrix-2/service-discovery/src/main/resources/application.properties @@ -0,0 +1,8 @@ +server.port=8260 + +eureka.instance.hostname=localhost +eureka.client.register-with-eureka=false +eureka.client.fetch-registry=false +eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/hystrix-2/service-discovery/src/main/resources/banner.txt b/hystrix-2/service-discovery/src/main/resources/banner.txt new file mode 100644 index 0000000..e12a88a --- /dev/null +++ b/hystrix-2/service-discovery/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Discovery == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/hystrix-2/service-discovery/src/main/resources/logback.xml b/hystrix-2/service-discovery/src/main/resources/logback.xml new file mode 100644 index 0000000..d4b7206 --- /dev/null +++ b/hystrix-2/service-discovery/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + + + logs/log-%d{yyyy-MM-dd}.%i.log + + + 64 MB + + + + + + DEBUG + + + true + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + DEBUG + + + + + + + + + diff --git a/hystrix-2/turbine-server/pom.xml b/hystrix-2/turbine-server/pom.xml new file mode 100755 index 0000000..ab2cd22 --- /dev/null +++ b/hystrix-2/turbine-server/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + turbine-server + Spring Cloud Sample Projects: Turbine Server + + + + org.springframework.cloud + spring-cloud-starter-turbine + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/hystrix-2/turbine-server/src/main/java/io/twostepsfromjava/cloud/turbine/Application.java b/hystrix-2/turbine-server/src/main/java/io/twostepsfromjava/cloud/turbine/Application.java new file mode 100644 index 0000000..02c472e --- /dev/null +++ b/hystrix-2/turbine-server/src/main/java/io/twostepsfromjava/cloud/turbine/Application.java @@ -0,0 +1,37 @@ +/*** + * 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 io.twostepsfromjava.cloud.turbine; + + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.turbine.EnableTurbine; + +/** + * TwoStepsFromJava Cloud -- Turbine服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableDiscoveryClient +@EnableTurbine +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} diff --git a/hystrix-2/turbine-server/src/main/resources/application.properties b/hystrix-2/turbine-server/src/main/resources/application.properties new file mode 100644 index 0000000..b4109a9 --- /dev/null +++ b/hystrix-2/turbine-server/src/main/resources/application.properties @@ -0,0 +1,12 @@ +server.port=8280 +management.port=8281 + +spring.application.name=TURBINE + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +turbine.app-config=MALL-WEB +turbine.cluster-name-expression="default" +turbine.combine-host-port=true + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/hystrix-2/turbine-server/src/main/resources/banner.txt b/hystrix-2/turbine-server/src/main/resources/banner.txt new file mode 100644 index 0000000..e12a88a --- /dev/null +++ b/hystrix-2/turbine-server/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Discovery == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/hystrix-2/turbine-server/src/main/resources/logback.xml b/hystrix-2/turbine-server/src/main/resources/logback.xml new file mode 100644 index 0000000..d4b7206 --- /dev/null +++ b/hystrix-2/turbine-server/src/main/resources/logback.xml @@ -0,0 +1,56 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + + + logs/log-%d{yyyy-MM-dd}.%i.log + + + 64 MB + + + + + + DEBUG + + + true + + + + + + + [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n + + UTF-8 + + + DEBUG + + + + + + + + + diff --git a/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandHelloFailure.java b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandHelloFailure.java new file mode 100644 index 0000000..484ec17 --- /dev/null +++ b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandHelloFailure.java @@ -0,0 +1,47 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + + +import com.netflix.hystrix.HystrixCommand; +import com.netflix.hystrix.HystrixCommandGroupKey; +import com.netflix.hystrix.HystrixCommandKey; +import com.netflix.hystrix.HystrixRequestCache; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ + +public class CommandHelloFailure extends HystrixCommand { + private String name; + + public CommandHelloFailure(String name) { + super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))); + this.name = name; + } + + @Override + protected String run() throws Exception { + return "Hello " + this.name + "!"; + } + + @Override + protected String getFallback() { + return "Hello Failure " + this.name + "!"; + } +} diff --git a/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandThatFailsFast.java b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandThatFailsFast.java new file mode 100644 index 0000000..573bef5 --- /dev/null +++ b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandThatFailsFast.java @@ -0,0 +1,48 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + + +import com.netflix.hystrix.HystrixCommand; +import com.netflix.hystrix.HystrixCommandGroupKey; + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ + +public class CommandThatFailsFast extends HystrixCommand { + private final boolean throwException; + + public CommandThatFailsFast(boolean throwException) { + super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); + this.throwException = throwException; + } + + @Override + protected String run() { + if (throwException) { + throw new RuntimeException("failure from CommandThatFailsFast"); + } else { + return "success"; + } + } + + @Override + protected boolean shouldNotBeWrapped(Throwable underlying) { + return super.shouldNotBeWrapped(underlying); + } +} diff --git a/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandUsingRequestCache.java b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandUsingRequestCache.java new file mode 100644 index 0000000..d157f11 --- /dev/null +++ b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/CommandUsingRequestCache.java @@ -0,0 +1,51 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + + +import com.netflix.hystrix.*; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ + +public class CommandUsingRequestCache extends HystrixCommand { + private String name; + + public CommandUsingRequestCache(String name) { + super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup")) + .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))); + this.name = name; + } + + @Override + protected String run() throws Exception { + return this.name; + } + + @Override + protected String getCacheKey() { + return this.name; + } + + public void evictCache(String name) { + HystrixRequestCache.getInstance(HystrixCommandKey.Factory.asKey("HelloWorld"), + HystrixConcurrencyStrategyDefault.getInstance()).clear(name); + } +} diff --git a/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/HelloFailureService.java b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/HelloFailureService.java new file mode 100644 index 0000000..48073ed --- /dev/null +++ b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/HelloFailureService.java @@ -0,0 +1,35 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ + +public class HelloFailureService { + + @HystrixCommand(groupKey = "ExampleGroup", fallbackMethod = "helloFallback") + public String hello(String name) { + return "Hello " + name + "!"; + } + + public String helloFallback(String name) { + return "Hello Failure " + name + "!"; + } +} diff --git a/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ObservableCommandHelloFailure.java b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ObservableCommandHelloFailure.java new file mode 100644 index 0000000..74e7f53 --- /dev/null +++ b/hystrix/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ObservableCommandHelloFailure.java @@ -0,0 +1,46 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + + +import com.netflix.hystrix.HystrixCommand; +import com.netflix.hystrix.HystrixCommandGroupKey; +import com.netflix.hystrix.HystrixObservableCommand; +import rx.Observable; + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ + +public class ObservableCommandHelloFailure extends HystrixObservableCommand { + private String name; + + public ObservableCommandHelloFailure(String name) { + super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))); + this.name = name; + } + + @Override + protected Observable construct() { + return Observable.just("Hello " + this.name + "!"); + } + + @Override + protected Observable resumeWithFallback() { + return Observable.just("Hello Failure " + this.name + "!"); + } +} diff --git a/stream/README.md b/stream/README.md new file mode 100644 index 0000000..fc320dd --- /dev/null +++ b/stream/README.md @@ -0,0 +1,6 @@ +# TwoStepsFromJava-Cloud-Stream + +Spring Cloud 示例项目:消息驱动式开发。 + + +Spring Cloud Release Trains: [Dalston.SR1](http://projects.spring.io/spring-cloud/) \ No newline at end of file diff --git a/stream/mall-web/pom.xml b/stream/mall-web/pom.xml new file mode 100755 index 0000000..1c2e97e --- /dev/null +++ b/stream/mall-web/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + mall-web + MS Blog Projects(Stream): Mall Web + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.cloud + spring-cloud-starter-ribbon + + + org.springframework.cloud + spring-cloud-starter-feign + + + org.springframework.cloud + spring-cloud-starter-hystrix + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/Application.java b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/Application.java new file mode 100644 index 0000000..fcf6902 --- /dev/null +++ b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/Application.java @@ -0,0 +1,37 @@ +/*** + * 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 io.twostepsfromjava.cloud.web; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.feign.EnableFeignClients; + +/** + * TwoStepsFromJava Cloud -- Mall Web Project + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableFeignClients +@EnableDiscoveryClient +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java new file mode 100644 index 0000000..ed312d5 --- /dev/null +++ b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/controller/ProductController.java @@ -0,0 +1,48 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.controller; + +import io.twostepsfromjava.cloud.web.mall.dto.ProductDto; +import io.twostepsfromjava.cloud.web.mall.service.ProductService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + + +/** + * Product Controller + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/products") +public class ProductController { + @Autowired + private ProductService productService; + + @RequestMapping(method = RequestMethod.GET) + public List list() { + return this.productService.findAll(); + } + + @RequestMapping(value = "/{itemCode}", method = RequestMethod.GET) + public ProductDto detail(@PathVariable String itemCode) { + return this.productService.loadByItemCode(itemCode); + } +} diff --git a/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/dto/ProductDto.java b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/dto/ProductDto.java new file mode 100644 index 0000000..d3da9c9 --- /dev/null +++ b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/dto/ProductDto.java @@ -0,0 +1,84 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.dto; + +import com.google.common.base.MoreObjects; + +/** + * 商品信息DTO对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class ProductDto { + private static final long serialVersionUID = 1L; + + // ======================================================================== + // fields ================================================================= + private String itemCode; // 商品货号 + private String name; // 商品名称 + private String bandName; // 商品品牌名称 + private int price; // 商品价格(分) + + // ======================================================================== + // constructor ============================================================ + public ProductDto() { + } + + public ProductDto(String itemCode, String name, String bandName, int price) { + this.itemCode = itemCode; + this.name = name; + this.bandName = bandName; + this.price = price; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("itemCode", this.getItemCode()) + .add("name", this.getName()) + .add("bandName", this.getBandName()) + .add("price", this.getPrice()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getBandName() { + return bandName; + } + public void setBandName(String bandName) { + this.bandName = bandName; + } + + public int getPrice() { + return price; + } + public void setPrice(int price) { + this.price = price; + } +} diff --git a/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsg.java b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsg.java new file mode 100644 index 0000000..51303a1 --- /dev/null +++ b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsg.java @@ -0,0 +1,67 @@ +/* + * 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 io.twostepsfromjava.cloud.web.mall.mq; + + +import com.google.common.base.MoreObjects; + +/** + * 商品消息 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductMsg { + /** 消息类型:更新商品,值为: {@value} */ + public static final String MA_UPDATE = "update"; + /** 消息类型:删除商品,值为: {@value} */ + public static final String MA_DELETE = "delete"; + + // ======================================================================== + // fields ================================================================= + private String action; + private String itemCode; + + // ======================================================================== + // constructor ============================================================ + public ProductMsg() { } + + public ProductMsg(String action, String itemCode) { + this.action = action; + this.itemCode = itemCode; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("itemCode", this.getItemCode()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } +} diff --git a/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsgListener.java b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsgListener.java new file mode 100644 index 0000000..7c668e8 --- /dev/null +++ b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/mq/ProductMsgListener.java @@ -0,0 +1,56 @@ +/* + * 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 io.twostepsfromjava.cloud.web.mall.mq; + + +import io.twostepsfromjava.cloud.web.mall.dto.ProductDto; +import io.twostepsfromjava.cloud.web.mall.service.ProductService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.cloud.stream.messaging.Sink; + + +/** + * 商品消息监听器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableBinding(Sink.class) +public class ProductMsgListener { + protected Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + protected ProductService productService; + + @StreamListener(Sink.INPUT) + public void onProductMsgSink(ProductMsg productMsg) { + if (ProductMsg.MA_UPDATE.equalsIgnoreCase(productMsg.getAction())) { + this.logger.debug("收到商品变更消息,商品货号: {}", productMsg.getItemCode()); + // 重新获取该商品信息 + ProductDto productDto = this.productService.loadByItemCode(productMsg.getItemCode()); + if (null != productDto) + this.logger.debug("重新获取到的商品信息为:{}", productDto); + else + this.logger.debug("货号为:{} 的商品不存在", productMsg.getItemCode()); + } else if (ProductMsg.MA_DELETE.equalsIgnoreCase(productMsg.getAction())) { + this.logger.debug("收到商品删除消息,所要删除商品货号为: {}", productMsg.getItemCode()); + } else { + this.logger.debug("收到未知商品消息: {}", productMsg); + } + } +} diff --git a/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java new file mode 100644 index 0000000..b0c769a --- /dev/null +++ b/stream/mall-web/src/main/java/io/twostepsfromjava/cloud/web/mall/service/ProductService.java @@ -0,0 +1,38 @@ +/*** + * 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 io.twostepsfromjava.cloud.web.mall.service; + +import io.twostepsfromjava.cloud.web.mall.dto.ProductDto; +import org.springframework.cloud.netflix.feign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import java.util.List; + + +/** + * Product Service + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@FeignClient("productservice") +public interface ProductService { + @RequestMapping(value = "/products", method = RequestMethod.GET) + List findAll(); + + @RequestMapping(value = "/products/{itemCode}", method = RequestMethod.GET) + ProductDto loadByItemCode(@PathVariable("itemCode") String itemCode); +} diff --git a/stream/mall-web/src/main/resources/application.properties b/stream/mall-web/src/main/resources/application.properties new file mode 100644 index 0000000..f76d718 --- /dev/null +++ b/stream/mall-web/src/main/resources/application.properties @@ -0,0 +1,18 @@ +server.port=8080 + +spring.application.name=MALL-WEB + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO +logging.level.io.twostepsfromjava=DEBUG + +# ===================================================================================================================== +# == stream / kafka == +# ===================================================================================================================== +spring.cloud.stream.bindings.input.destination=twostepsfromjava-cloud-producttopic +spring.cloud.stream.bindings.input.content-type=application/json +spring.cloud.stream.bindings.input.group=mallWebGroup +spring.cloud.stream.kafka.binder.brokers=localhost +spring.cloud.stream.kafka.binder.defaultBrokerPort=9092 +spring.cloud.stream.kafka.binder.zkNodes=localhost \ No newline at end of file diff --git a/stream/mall-web/src/main/resources/banner.txt b/stream/mall-web/src/main/resources/banner.txt new file mode 100644 index 0000000..2d4682f --- /dev/null +++ b/stream/mall-web/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Consumer == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/stream/parent/pom.xml b/stream/parent/pom.xml new file mode 100644 index 0000000..118f600 --- /dev/null +++ b/stream/parent/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + MS Blog Projects(Stream): Parent Pom + pom + + + UTF-8 + + + + + + org.springframework.cloud + spring-cloud-dependencies + Dalston.SR3 + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/stream/pom.xml b/stream/pom.xml new file mode 100755 index 0000000..0552fe8 --- /dev/null +++ b/stream/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + parent + + + twostepsfromjava-clouds + 1.0.0-SNAPSHOT + MS Blog Projects -- Stream + pom + + + parent + service-discovery + + product-service + user-service + + mall-web + + diff --git a/stream/product-service/pom.xml b/stream/product-service/pom.xml new file mode 100755 index 0000000..3f0ce03 --- /dev/null +++ b/stream/product-service/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + product-service + MS Blog Projects(Stream): Product Service Server + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/stream/product-service/src/main/java/io/twostepsfromjava/cloud/Application.java b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/Application.java new file mode 100644 index 0000000..56b1480 --- /dev/null +++ b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/Application.java @@ -0,0 +1,38 @@ +/*** + * 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 io.twostepsfromjava.cloud; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.messaging.Source; + +/** + * TwoStepsFromJava Cloud -- ProductDto Service 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableDiscoveryClient +@EnableBinding(Source.class) +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/api/ProductEndpoint.java b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/api/ProductEndpoint.java new file mode 100644 index 0000000..be39d8d --- /dev/null +++ b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/api/ProductEndpoint.java @@ -0,0 +1,59 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.api; + +import io.twostepsfromjava.cloud.product.dto.ProductDto; +import io.twostepsfromjava.cloud.product.service.ProductService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * ProductDto API服务 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/products") +public class ProductEndpoint { + protected Logger logger = LoggerFactory.getLogger(ProductEndpoint.class); + + @Autowired + ProductService productService; + + @RequestMapping(method = RequestMethod.GET) + public List list() { + return this.productService.findAll(); + } + + @RequestMapping(value = "/{itemCode}", method = RequestMethod.GET) + public ProductDto detail(@PathVariable String itemCode) { + return this.productService.findOne(itemCode); + } + + // FIXME: 该端点仅仅是用来测试消息发送,并不包含任何业务逻辑处理 + @RequestMapping(value = "/{itemCode}", method = RequestMethod.POST) + public ProductDto save(@PathVariable String itemCode) { + ProductDto productDto = this.productService.findOne(itemCode); + if (null != productDto) { + this.productService.save(productDto); + } + return productDto; + } +} diff --git a/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/dto/ProductDto.java b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/dto/ProductDto.java new file mode 100644 index 0000000..500fe43 --- /dev/null +++ b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/dto/ProductDto.java @@ -0,0 +1,84 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.dto; + +import com.google.common.base.MoreObjects; + +/** + * 商品信息DTO对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class ProductDto { + private static final long serialVersionUID = 1L; + + // ======================================================================== + // fields ================================================================= + private String itemCode; // 商品货号 + private String name; // 商品名称 + private String bandName; // 商品品牌名称 + private int price; // 商品价格(分) + + // ======================================================================== + // constructor ============================================================ + public ProductDto() { + } + + public ProductDto(String itemCode, String name, String bandName, int price) { + this.itemCode = itemCode; + this.name = name; + this.bandName = bandName; + this.price = price; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("itemCode", this.getItemCode()) + .add("name", this.getName()) + .add("bandName", this.getBandName()) + .add("price", this.getPrice()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getBandName() { + return bandName; + } + public void setBandName(String bandName) { + this.bandName = bandName; + } + + public int getPrice() { + return price; + } + public void setPrice(int price) { + this.price = price; + } +} diff --git a/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/entity/Product.java b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/entity/Product.java new file mode 100644 index 0000000..ca56fce --- /dev/null +++ b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/entity/Product.java @@ -0,0 +1,84 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.entity; + +import com.google.common.base.MoreObjects; + +/** + * 商品信息实体对象 + * + * @author CD826(CD826Dong@gamil.com) + * @since 1.0.0 + */ +public class Product { + private static final long serialVersionUID = 1L; + + // ======================================================================== + // fields ================================================================= + private String itemCode; // 商品货号 + private String name; // 商品名称 + private String bandName; // 商品品牌名称 + private int price; // 商品价格(分) + + // ======================================================================== + // constructor ============================================================ + public Product() { + } + + public Product(String itemCode, String name, String bandName, int price) { + this.itemCode = itemCode; + this.name = name; + this.bandName = bandName; + this.price = price; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("itemCode", this.getItemCode()) + .add("name", this.getName()) + .add("bandName", this.getBandName()) + .add("price", this.getPrice()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getBandName() { + return bandName; + } + public void setBandName(String bandName) { + this.bandName = bandName; + } + + public int getPrice() { + return price; + } + public void setPrice(int price) { + this.price = price; + } +} diff --git a/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/mq/ProductMsg.java b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/mq/ProductMsg.java new file mode 100644 index 0000000..4d18bf7 --- /dev/null +++ b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/mq/ProductMsg.java @@ -0,0 +1,67 @@ +/* + * 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 io.twostepsfromjava.cloud.product.mq; + + +import com.google.common.base.MoreObjects; + +/** + * 商品消息 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +public class ProductMsg { + /** 消息类型:更新商品,值为: {@value} */ + public static final String MA_UPDATE = "update"; + /** 消息类型:删除商品,值为: {@value} */ + public static final String MA_DELETE = "delete"; + + // ======================================================================== + // fields ================================================================= + private String action; + private String itemCode; + + // ======================================================================== + // constructor ============================================================ + public ProductMsg() { } + + public ProductMsg(String action, String itemCode) { + this.action = action; + this.itemCode = itemCode; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("action", this.getAction()) + .add("itemCode", this.getItemCode()).toString(); + } + + // ================================================================== + // setter/getter ==================================================== + public String getAction() { + return action; + } + public void setAction(String action) { + this.action = action; + } + + public String getItemCode() { + return itemCode; + } + public void setItemCode(String itemCode) { + this.itemCode = itemCode; + } +} diff --git a/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/service/ProductService.java b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/service/ProductService.java new file mode 100644 index 0000000..29a1826 --- /dev/null +++ b/stream/product-service/src/main/java/io/twostepsfromjava/cloud/product/service/ProductService.java @@ -0,0 +1,115 @@ +/*** + * 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 io.twostepsfromjava.cloud.product.service; + +import io.twostepsfromjava.cloud.product.dto.ProductDto; +import io.twostepsfromjava.cloud.product.mq.ProductMsg; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.stream.messaging.Source; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + + +/** + * 商品服务 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@Service +public class ProductService { + protected Logger logger = LoggerFactory.getLogger(ProductService.class); + + private Source source; + private List productList; + + @Autowired + public ProductService(Source source) { + this.source = source; + this.productList = this.buildProducts(); + } + + /** + * 获取商品列表 + * @return + */ + public List findAll() { + return this.productList; + } + + /** + * 根据ItemCode获取 + * @param itemCode + * @return + */ + public ProductDto findOne(String itemCode) { + for (ProductDto productDto : this.productList) { + if (productDto.getItemCode().equalsIgnoreCase(itemCode)) + return productDto; + } + + return null; + } + + /** + * 保存或更新商品信息 + * @param productDto + * @return + */ + public ProductDto save(ProductDto productDto) { + // TODO: 实现商品保存处理 + for (ProductDto sourceProductDto : this.productList) { + if (sourceProductDto.getItemCode().equalsIgnoreCase(productDto.getItemCode())) { + sourceProductDto.setName(sourceProductDto.getName() + "-new"); + sourceProductDto.setPrice(sourceProductDto.getPrice() + 100); + productDto = sourceProductDto; + break; + } + } + + // 发送商品消息 + this.sendMsg(ProductMsg.MA_UPDATE, productDto.getItemCode()); + + return productDto; + } + + /** + * 具体消息发送的实现 + * @param msgAction 消息类型 + * @param itemCode 商品货号 + */ + protected void sendMsg(String msgAction, String itemCode) { + ProductMsg productMsg = new ProductMsg(msgAction, itemCode); + this.logger.debug("发送商品消息:{} ", productMsg); + + // 发送消息 + this.source.output().send(MessageBuilder.withPayload(productMsg).build()); + } + + protected List buildProducts() { + List products = new ArrayList<>(); + products.add(new ProductDto("item-1", "测试商品-1", "TwoStepsFromJava", 100)); + products.add(new ProductDto("item-2", "测试商品-2", "TwoStepsFromJava", 200)); + products.add(new ProductDto("item-3", "测试商品-3", "TwoStepsFromJava", 300)); + products.add(new ProductDto("item-4", "测试商品-4", "TwoStepsFromJava", 400)); + products.add(new ProductDto("item-5", "测试商品-5", "TwoStepsFromJava", 500)); + products.add(new ProductDto("item-6", "测试商品-6", "TwoStepsFromJava", 600)); + return products; + } +} diff --git a/stream/product-service/src/main/resources/application.properties b/stream/product-service/src/main/resources/application.properties new file mode 100644 index 0000000..55a76e8 --- /dev/null +++ b/stream/product-service/src/main/resources/application.properties @@ -0,0 +1,17 @@ +server.port=2100 + +spring.application.name=productservice + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO +logging.level.io.twostepsfromjava=DEBUG + +# ===================================================================================================================== +# == stream / kafka == +# ===================================================================================================================== +spring.cloud.stream.bindings.output.destination=twostepsfromjava-cloud-producttopic +spring.cloud.stream.bindings.output.content-type=application/json +spring.cloud.stream.kafka.binder.brokers=localhost +spring.cloud.stream.kafka.binder.defaultBrokerPort=9092 +spring.cloud.stream.kafka.binder.zkNodes=localhost \ No newline at end of file diff --git a/stream/product-service/src/main/resources/banner.txt b/stream/product-service/src/main/resources/banner.txt new file mode 100644 index 0000000..a692d74 --- /dev/null +++ b/stream/product-service/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Product == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/stream/service-discovery/pom.xml b/stream/service-discovery/pom.xml new file mode 100755 index 0000000..56771c3 --- /dev/null +++ b/stream/service-discovery/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + service-discovery + MS Blog Projects(Stream): Eureka Server + + + + org.springframework.cloud + spring-cloud-starter-eureka-server + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/stream/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java b/stream/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java new file mode 100644 index 0000000..31a533d --- /dev/null +++ b/stream/service-discovery/src/main/java/io/twostepsfromjava/cloud/service/discovery/Application.java @@ -0,0 +1,35 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.discovery; + + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +/** + * TwoStepsFromJava Cloud -- Service Discoery 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableEurekaServer +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + new SpringApplicationBuilder(Application.class).web(true).run(args); + } + +} diff --git a/stream/service-discovery/src/main/resources/application.properties b/stream/service-discovery/src/main/resources/application.properties new file mode 100644 index 0000000..269e732 --- /dev/null +++ b/stream/service-discovery/src/main/resources/application.properties @@ -0,0 +1,8 @@ +server.port=8260 + +eureka.instance.hostname=localhost +eureka.client.register-with-eureka=false +eureka.client.fetch-registry=false +eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/stream/service-discovery/src/main/resources/banner.txt b/stream/service-discovery/src/main/resources/banner.txt new file mode 100644 index 0000000..e12a88a --- /dev/null +++ b/stream/service-discovery/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- Discovery == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file diff --git a/stream/user-service/pom.xml b/stream/user-service/pom.xml new file mode 100755 index 0000000..50e85ee --- /dev/null +++ b/stream/user-service/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + + twostepsfromjava.cloud + twostepsfromjava-cloud-parent + 1.0.0-SNAPSHOT + ../parent + + + user-service + MS Blog Projects(Stream): User Service Server + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-eureka + + + + ${project.groupId} + service-api + ${project.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/stream/user-service/src/main/java/io/twostepsfromjava/cloud/service/user/Application.java b/stream/user-service/src/main/java/io/twostepsfromjava/cloud/service/user/Application.java new file mode 100644 index 0000000..53bd46c --- /dev/null +++ b/stream/user-service/src/main/java/io/twostepsfromjava/cloud/service/user/Application.java @@ -0,0 +1,35 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.user; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * TwoStepsFromJava Cloud -- User Service 服务器 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@EnableDiscoveryClient +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/stream/user-service/src/main/java/io/twostepsfromjava/cloud/service/user/api/UserEndpoint.java b/stream/user-service/src/main/java/io/twostepsfromjava/cloud/service/user/api/UserEndpoint.java new file mode 100644 index 0000000..b1bdf74 --- /dev/null +++ b/stream/user-service/src/main/java/io/twostepsfromjava/cloud/service/user/api/UserEndpoint.java @@ -0,0 +1,42 @@ +/*** + * 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 io.twostepsfromjava.cloud.service.user.api; + +import io.twostepsfromjava.cloud.user.dto.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + + +/** + * User API服务 + * + * @author CD826(CD826Dong@gmail.com) + * @since 1.0.0 + */ +@RestController +@RequestMapping("/users") +public class UserEndpoint { + protected Logger logger = LoggerFactory.getLogger(UserEndpoint.class); + + @Value("${server.port:2200}") + private int serverPort = 2200; + + @RequestMapping(value = "/{loginName}", method = RequestMethod.GET) + public User detail(@PathVariable String loginName) { + String memos = "I come form " + this.serverPort; + return new User(loginName, loginName, "/avatar/default.png", memos); + } +} diff --git a/stream/user-service/src/main/resources/application.properties b/stream/user-service/src/main/resources/application.properties new file mode 100644 index 0000000..f015575 --- /dev/null +++ b/stream/user-service/src/main/resources/application.properties @@ -0,0 +1,7 @@ +server.port=2200 + +spring.application.name=USER-SERVICE + +eureka.client.service-url.defaultZone=http://localhost:8260/eureka + +logging.level.org.springframework=INFO \ No newline at end of file diff --git a/stream/user-service/src/main/resources/banner.txt b/stream/user-service/src/main/resources/banner.txt new file mode 100644 index 0000000..6d6d6bb --- /dev/null +++ b/stream/user-service/src/main/resources/banner.txt @@ -0,0 +1,13 @@ +======================================================================================================================= +== == +== == +== _______ _____ ______ _ _____ _ ____ _ _ _____ == +== |__ __|/ ____|| ____| | | / ____|| | / __ \ | | | || __ \ == +== | | | (___ | |__ | | ______ | | | | | | | || | | || | | | == +== | | \___ \ | __|_ | ||______|| | | | | | | || | | || | | | == +== | | ____) || | | |__| | | |____ | |____| |__| || |__| || |__| | == +== |_| |_____/ |_| \____/ \_____||______|\____/ \____/ |_____/ -- User == +== == +== == +======================================================================================================================= +:: twostepsfromjava.io :: v1.0.0.BUILD-SNAPSHOT BUILD-BY: CD826 \ No newline at end of file