feat: integrated example local version initialized (#2711)

* Integrated example local version business and docs initialized

* polish code

* add frontend module and refactor distributed tx scenarios

* resolving front-end cross-origin

* rocketmq frontend

* sentinel frontend

* feat: localized deployment for integrated-example
pull/2825/head
Yuyao Huang 2 years ago committed by GitHub
parent de3cfb10cb
commit bb5c6d0e92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,376 +1,376 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/>
</parent>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<name>Spring Cloud Alibaba</name>
<description>Spring Cloud Alibaba</description>
<url>https://github.com/alibaba/spring-cloud-alibaba</url>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<name>Spring Cloud Alibaba</name>
<description>Spring Cloud Alibaba</description>
<url>https://github.com/alibaba/spring-cloud-alibaba</url>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://github.com/alibaba/spring-cloud-alibaba</url>
<connection>
scm:git:git://github.com/alibaba/spring-cloud-alibaba.git
</connection>
<developerConnection>
scm:git:ssh://git@github.com/alibaba/spring-cloud-alibaba.git
</developerConnection>
<tag>HEAD</tag>
</scm>
<scm>
<url>https://github.com/alibaba/spring-cloud-alibaba</url>
<connection>
scm:git:git://github.com/alibaba/spring-cloud-alibaba.git
</connection>
<developerConnection>
scm:git:ssh://git@github.com/alibaba/spring-cloud-alibaba.git
</developerConnection>
<tag>HEAD</tag>
</scm>
<developers>
<developer>
<name>xiaojing</name>
<email>flystar32@163.com</email>
</developer>
<developer>
<name>Jim Fang</name>
<email>fangjian0423@gmail.com</email>
<organization>Alibaba</organization>
<url>https://github.com/fangjian0423</url>
</developer>
<developer>
<name>xiaolongzuo</name>
<email>150349407@qq.com</email>
</developer>
<developer>
<name>hengyunabc</name>
<email>hengyunabc@gmail.com</email>
</developer>
<developer>
<id>mercyblitz</id>
<name>Mercy Ma</name>
<email>mercyblitz@gmail.com</email>
<organization>Alibaba</organization>
<url>https://github.com/mercyblitz</url>
</developer>
<developer>
<name>yunzheng</name>
<email>yunzheng1228@gmail.com</email>
</developer>
<developer>
<id>theonefx</id>
<name>theonefx</name>
<email>chenxilzx1@gmail.com</email>
<organization>Alibaba</organization>
<url>https://github.com/theonefx</url>
</developer>
</developers>
<developers>
<developer>
<name>xiaojing</name>
<email>flystar32@163.com</email>
</developer>
<developer>
<name>Jim Fang</name>
<email>fangjian0423@gmail.com</email>
<organization>Alibaba</organization>
<url>https://github.com/fangjian0423</url>
</developer>
<developer>
<name>xiaolongzuo</name>
<email>150349407@qq.com</email>
</developer>
<developer>
<name>hengyunabc</name>
<email>hengyunabc@gmail.com</email>
</developer>
<developer>
<id>mercyblitz</id>
<name>Mercy Ma</name>
<email>mercyblitz@gmail.com</email>
<organization>Alibaba</organization>
<url>https://github.com/mercyblitz</url>
</developer>
<developer>
<name>yunzheng</name>
<email>yunzheng1228@gmail.com</email>
</developer>
<developer>
<id>theonefx</id>
<name>theonefx</name>
<email>chenxilzx1@gmail.com</email>
<organization>Alibaba</organization>
<url>https://github.com/theonefx</url>
</developer>
</developers>
<properties>
<!-- Project revision -->
<revision>2.2.9-SNAPSHOT</revision>
<properties>
<!-- Project revision -->
<revision>2.2.9-SNAPSHOT</revision>
<!-- Spring Cloud -->
<spring.cloud.version>Hoxton.SR12</spring.cloud.version>
<!-- Spring Cloud -->
<spring.cloud.version>Hoxton.SR12</spring.cloud.version>
<!-- Apache Dubbo -->
<dubbo.version>2.7.15</dubbo.version>
<curator.version>4.0.1</curator.version>
<!-- Apache Dubbo -->
<dubbo.version>2.7.15</dubbo.version>
<curator.version>4.0.1</curator.version>
<!-- Apache RocketMQ -->
<rocketmq.starter.version>2.0.4</rocketmq.starter.version>
<rocketmq.version>4.9.3</rocketmq.version>
<!-- Apache RocketMQ -->
<rocketmq.starter.version>2.0.4</rocketmq.starter.version>
<rocketmq.version>4.9.3</rocketmq.version>
<!-- Maven Plugin Versions -->
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
<maven-source-plugin.version>2.2.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<flatten-maven-plugin.version>1.1.0</flatten-maven-plugin.version>
<gmavenplus-plugin.version>1.6</gmavenplus-plugin.version>
<jacoco.version>0.8.3</jacoco.version>
</properties>
<!-- Maven Plugin Versions -->
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
<maven-source-plugin.version>2.2.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<flatten-maven-plugin.version>1.1.0</flatten-maven-plugin.version>
<gmavenplus-plugin.version>1.6</gmavenplus-plugin.version>
<jacoco.version>0.8.3</jacoco.version>
</properties>
<modules>
<module>spring-cloud-alibaba-dependencies</module>
<module>spring-cloud-alibaba-examples</module>
<module>spring-cloud-alibaba-docs</module>
<module>spring-cloud-alibaba-starters</module>
<module>spring-cloud-alibaba-coverage</module>
</modules>
<modules>
<module>spring-cloud-alibaba-dependencies</module>
<module>spring-cloud-alibaba-examples</module>
<module>spring-cloud-alibaba-docs</module>
<module>spring-cloud-alibaba-starters</module>
<module>spring-cloud-alibaba-coverage</module>
</modules>
<dependencyManagement>
<dependencies>
<dependencyManagement>
<dependencies>
<!-- Spring Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Dubbo Dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Dubbo Dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-actuator</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-actuator</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>${rocketmq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
<version>${rocketmq.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>${rocketmq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
<version>${rocketmq.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<useProjectReferences>false</useProjectReferences>
<additionalConfig>
<file>
<name>.settings/org.eclipse.jdt.ui.prefs</name>
<location>
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.ui.prefs
</location>
</file>
<file>
<name>.settings/org.eclipse.jdt.core.prefs</name>
<location>
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.core.prefs
</location>
</file>
</additionalConfig>
</configuration>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<!-- Checkstyle rules inherited from spring-cloud-build -->
<suppressionsLocation>
${session.executionRootDirectory}/eclipse/checkstyle-suppressions.xml
</suppressionsLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<violationSeverity>warning</violationSeverity>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<source>1.8</source>
<target>1.8</target>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<useProjectReferences>false</useProjectReferences>
<additionalConfig>
<file>
<name>.settings/org.eclipse.jdt.ui.prefs</name>
<location>
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.ui.prefs
</location>
</file>
<file>
<name>.settings/org.eclipse.jdt.core.prefs</name>
<location>
${maven.multiModuleProjectDirectory}/eclipse/org.eclipse.jdt.core.prefs
</location>
</file>
</additionalConfig>
</configuration>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<!-- Checkstyle rules inherited from spring-cloud-build -->
<suppressionsLocation>
${maven.multiModuleProjectDirectory}/eclipse/checkstyle-suppressions.xml
</suppressionsLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<violationSeverity>warning</violationSeverity>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<source>1.8</source>
<target>1.8</target>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<inherited>true</inherited>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</profile>
</profiles>
<distributionManagement>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</profile>
</profiles>
</project>

@ -0,0 +1,10 @@
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
main:
allow-bean-definition-overriding: true
mybatis:
configuration:
map-underscore-to-camel-case: true

@ -0,0 +1,3 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/integrated_account?useSSL=false&characterEncoding=utf8

@ -0,0 +1,18 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/integrated_praise?useSSL=false&characterEncoding=utf8
cloud:
stream:
bindings:
praise-input:
destination: PRAISE-TOPIC-01
content-type: application/json
group: praise-consumer-group-PRAISE-TOPIC-01
rocketmq:
binder:
name-server: localhost:9876
bindings:
praise-input:
consumer:
pullInterval: 4000
pullBatchSize: 4

@ -0,0 +1,28 @@
spring:
cloud:
gateway:
routes:
- id: placeOrder
uri: lb://integrated-order
predicates:
- Path=/order/create
- id: queryStorage
uri: lb://integrated-storage
predicates:
- Path=/storage/
- id: queryAccount
uri: lb://integrated-account
predicates:
- Path=/account/
- id: praiseItemRocketMQ
uri: lb://integrated-provider
predicates:
- Path=/praise/rocketmq
- id: praiseItemSentinel
uri: lb://integrated-provider
predicates:
- Path=/praise/sentinel
- id: queryPraise
uri: lb://integrated-consumer
predicates:
- Path=/praise/query

@ -0,0 +1,3 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/integrated_order?useSSL=false&characterEncoding=utf8

@ -0,0 +1,14 @@
spring:
cloud:
stream:
bindings:
praise-output:
destination: PRAISE-TOPIC-01
content-type: application/json
rocketmq:
binder:
name-server: localhost:9876
bindings:
praise-output:
producer:
group: test

@ -0,0 +1,3 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/integrated_storage?useSSL=false&characterEncoding=utf8

@ -0,0 +1,2 @@
# Spring Cloud Alibaba Containerized Deployment Best Practices | Docker-Compose Container Edition
Under Construction.....

@ -0,0 +1,191 @@
## Spring Cloud Alibaba Containerized Deployment Best Practices | Local Deployment Version
## Preparation
### Environment declaration
Before running the local example, you need to ensure that the following base environment is available locally. If you do not have a current environment locally, the following step-by-step build will demonstrate the build process.
- Nacos server
- Seata server
- RocketMQ server
- MySQL server
### Component Service Versions
To download and unpack the component versions of this project, please go to the release pages of the respective communities.
- [Nacos: version 2.1.0](https://github.com/alibaba/nacos/releases)
- [Seata: version 1.5.1](https://github.com/seata/seata/releases)
- [RocketMQ: version 4.9.4](https://github.com/apache/rocketmq/releases)
- MySQL: version 5.7
### Database configuration
The following starts the local environment build preparation, before the database configuration starts, please make sure that the MySQL server is turned on.
#### Initializing Business Tables
For the first scenario, the orders, accounts and inventory microservices all need their own databases, while the second scenario simulating likes also needs a database to store the likes information.
Run the sql script `spring-cloud-alibaba-examples/integrated-example/sql/init.sql` to create the environment required for the business and the Seata-related tables in one click.
### Nacos configuration
Now that the database services are configured, you need to configure the Nacos configuration centre with all the microservice configuration files.
#### Nacos startup
For the purpose of this example, Nacos is started in ``standalone'' mode. Go to the Nacos unpacked directory and execute the following command.
```sh
#Linux/Mac environment
sh bin/startup.sh -m standalone
#If you are in Ubuntu and the above command gives you an error saying [[symbol not found, you can run the following command
bash bin/startup.sh -m standalone
#Win environment
. \bin\startup.cmd -m standalone
```
#### Adding configuration files
Before bulk importing the configuration, change the datasource configuration (username and password) in `integrated-example/config/datasource-config.yaml`.
Afterwards, run `spring-cloud-alibaba-examples/integrated-example/scripts/nacos-config-quick.sh` to complete the one-click import of all microservice configurations.
### Seata configuration
Once the Nacos service registry and configuration centre have been deployed, here is the configuration of the Seata server.
Seata's db mode requires additional configuration of the database information and modification of the Seata Server configuration file, which has been merged in the new version compared to the old one.
#### Start Seata Server
Go to the seata directory after the release and execute the following command.
```sh
#Linux/Mac environment
sh . /bin/seata-server.sh
#Win environment
bin\seata-server.bat
```
### RocketMQ configuration
Once the Seata service is started, you can start the RocketMQ NameServer and Broker services.
Go to the unpacked rocketmq directory after the release and execute the following command.
#### Start the NameServer
```sh
#Linux/Mac environment
sh bin/mqnamesrv
#Win environment
. \bin\mqnamesrv.cmd
```
#### Start Broker
```sh
#Linux/Mac environment
sh bin/mqbroker
#Win environment
. \bin\mqbroker.cmd
```
## Run the demo
After the preparation work is done, you can run the demo to experience the user order (distributed transaction capability) and simulate the high traffic volume (meltdown limit and peak shaving capability) depending on different usage scenarios.
The first step is to start the `integrated_frontend` and `integrated_gateway` projects respectively.
- The gateway module is the gateway to the entire best practice instance.
- frontend is the simple front-end page for the best practice.
### Distributed transaction capability
#### scenario description
For the distributed transaction capability, we provide a scenario **where a user places an order for goods** and after placing the order.
- First request the inventory module and deduct the inventory
- Deducts the account balance
- Generate order information to return a response
##### start test
Start the `integrated_storage`, `integrated_account`, `integrated_order` microservices separately.
Visit `http://127.0.0.1:8080/order` to experience the corresponding scenario.
By clicking directly on the order button to submit the form, we simulate the client sending a request to the gateway to create an order.
- The user's userId is admin
- The user places an order for item number 1
- The number of items purchased in this order is 1
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914153234414.png)
In this demo, for demonstration purposes, the unit price of each item is 2.
In the previous preparation, when **initialising the business database table** we created a new user userId = admin with a balance of $3 and a new item numbered 1 with 100 items in stock.
So by doing the above, we create an order, deducting the number of units in stock for item number 1 (100-1=99) and deducting the balance of the admin user (3-2=1).
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914153126925.png)
If the same interface is requested again, again the stock is deducted first (99-1=98), but an exception is thrown because the admin user's balance is insufficient and is caught by Seata, which performs a two-stage commit of the distributed transaction and rolls back the transaction.
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914153313127.png)
You can see that the database still has 99 records in stock because of the rollback.
### Melt limit, peak shaving capability
#### Scenario description
For service fusion limiting in the context of high traffic and peak and valley reduction, we provide a scenario where **users like an item**. In this scenario, we provide two ways to deal with high traffic.
- Sentinel binds a specified gateway route on the gateway side for fusion degradation of the service.
- RocketMQ performs traffic clipping, where the producer sends messages to RocketMQ during high traffic requests, while the consumer pulls and consumes at a configurable consumption rate, reducing the pressure of high traffic direct requests to the database to increase the number of likes requested.
#### startup tests
Start the `integrated_provider` and `integrated_consumer` modules separately.
- Sentinel service meltdown downgrade
Visit `http://127.0.0.1:8080/sentinel` to experience the corresponding scenario.
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914155720469.png)
The Gateway routing point service has a flow limit rule of 5, while 10 concurrent requests are simulated on the front-end through asynchronous processing.
So you can see that Sentinel is fusing the service on the Gateway side to return a fallback to the client for the extra traffic, while the number of likes in the database is updated (+5).
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914155755103.png)
- RocketMQ does peak and valley reduction
Visit `http://127.0.0.1:8080/rocketmq` to experience the corresponding scenario.
As we have previously configured the consumption rate and interval of the `integrated-consumer` consumer module in Nacos, we simulate 1000 requests for likes at the click of a button, and for 1000 requests for likes, the `integrated_provider`
In the consumer module, we consume at the configured consumption rate and update the database with the product data, simulating the RocketMQ peak-shaving feature in heavy traffic.
You can see that the number of likes in the database is being dynamically updated.
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914155815191.png)
## Other
This example **is just a selection of the typical features of each component to serve the application scenario**.
Of course, there is more to each component than what is demonstrated in the best practices, so if you are interested or want to go deeper, you are welcome to study the individual example documentation for each component.
- Nacos Examples
- [nacos-config-example](../../nacos-example/nacos-config-example/readme-zh.md)
- [nacos-discovery-example](../../nacos-example/nacos-discovery-example/readme-zh.md)
- [Sentinel-Core-Example](../../sentinel-example/sentinel-core-example/readme-zh.md)
- [Seata Examples](../../seata-example/readme-zh.md)
- [RocketMQ Example](../../rocketmq-example/readme-zh.md)

@ -0,0 +1,85 @@
# Integrated Example
## Project Description
This project is a demo of Spring Cloud Alibaba containerized deployment best practices, and is an example project integrating Spring Cloud Alibaba components (Nacos, Sentinel, Seata, RocketMQ).
The main components used and their usage features are as follows.
- Spring Cloud Gateway:gateway
- Nacos:configuration centre and service registry
- Sentinel:fusion flow limiting
- Seata:Distributed Transactions
- RocketMQ:message queues for peak and valley reduction
- Docker:Microservices Containerized Deployment
- Kubernetes Helm Chart
![Overall Overview](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220816004541921.png)
## Application Scenario Description
In this demo, we provide two business scenarios.
1) A scenario where a user places an order for goods and after placing the order.
- First request the inventory module to deduct the inventory
- Deduct the account balance
- Generate order information and return a response
2) The user likes the goods (simulating the producer-consumer application scenario of MQ) and returns the details (number of likes, etc.) after the goods have been liked.
### Detailed description of the component
1) In which the scenario where the user places an order for the goods mainly uses Seata to perform distributed transactions to represent the capabilities.
2) The scenario where the user likes a product simulates a high traffic environment with Sentinel for flow limiting or RocketMQ for peak shaving. In this scenario, we provide two ways to deal with high traffic.
- Sentinel binds a specified gateway route on the gateway side for service fusion degradation.
- RocketMQ performs peak-shaving, where producers send messages to RocketMQ and consumers pull and consume at configurable consumption rates, reducing the pressure of high traffic direct requests to the database and increasing the number of likes.
#### SpringCloud Gateway
A gateway to the microservices module.
Spring Cloud GateWay integrates with Nacos, enabling dynamic routing configuration.
By listening for changes to the Nacos configuration, the service gateway routing configuration is dynamically refreshed so that each time the routing information changes, there is no need to modify the configuration file and then restart the service.
#### Nacos
The configuration centre for each microservice, the service registry.
- Configuration Centre
- Shared configuration: MySQL data source related information configuration.
- Registration Centre
- All microservice modules are registered to Nacos for service registration and discovery.
- Integration with SpringCloud Gateway gateway.
#### Seata
Seata-based AT model for distributed transaction processing for the Inventory, Accounts and Orders modules.
Roll back transactions whenever stock is low/account balance is low.
#### Sentinel
Service fusion flow limiting for point and click scenarios.
Integrates Nacos Configuration Center with Spring Cloud Gateway to enable dynamic configuration of fused flow limiting rules for specified routing rules.
#### RocketMQ
Used for peaks and valleys reduction of like service traffic.
By sending high volume like requests from the producer to the mq, the consumer module pulls from the mq and consumes them with a certain frequency, rather than simply fusing and limiting the degradation of the service directly, enabling RocketMQ's ability to shave peaks and valleys for high volume traffic.
## Release Notes
This project provides a [local-deployment](local-deployment.md) and a [Kubernetes Helm-Chart version](kubernetes-deployment.md).
- To learn how to configure the components and build the complete environment, we recommend learning the [local-deployment](local-deployment.md).
- If you want to quickly experience the components on a K8S cluster and skip the process of deploying each component, please check out the [Kubernetes Helm-Chart version](kubernetes-deployment.md).

@ -0,0 +1,2 @@
# Spring Cloud Alibaba容器化部署最佳实践 | Kubernetes Helm-Chart 版本
建设中

@ -0,0 +1,191 @@
# Spring Cloud Alibaba 容器化部署最佳实践 | 本地部署版本
## 准备工作
### 环境声明
在运行本地示例之前,需要保证本机具备以下的基础环境,如果您的本地没有当前的环境,下面会一步步进行搭建,演示搭建过程。
- Nacos 服务端
- Seata 服务端
- RocketMQ 服务端
- MySQL 服务端
### 组件服务版本
本项目的各个组件版本请移步至各个社区的 release 页面进行下载并解压。
- [Nacos: 2.1.0 版本](https://github.com/alibaba/nacos/releases)
- [Seata: 1.5.1 版本](https://github.com/seata/seata/releases)
- [RocketMQ: 4.9.4 版本](https://github.com/apache/rocketmq/releases)
- MySQL: 5.7 版本
### 数据库配置
下面开始本地环境搭建准备在数据库配置开始之前请确保MySQL的服务端开启。
#### 初始化业务表
针对第一个场景,订单、账户、库存微服务都需要各自的数据库,而第二个场景模拟点赞也需要存储点赞信息的数据库。
运行 `spring-cloud-alibaba-examples/integrated-example/sql/init.sql` 的 sql 脚本一键创建业务所需的环境以及 Seata 相关的表。
### Nacos配置
至此,数据库的服务配置完毕,下面需要配置 Nacos 的配置中心有关所有的微服务配置文件。
#### Nacos启动
为了便于 example 的演示,这里采用 Nacos 的`standalone`模式启动,进入到 Nacos 解压后的目录下,执行如下命令。
```sh
#Linux/Mac环境
sh bin/startup.sh -m standalone
#如果您是Ubuntu环境执行上述命令启动报错提示[[符号找不到,可以执行如下的命令
bash bin/startup.sh -m standalone
#Win环境
.\bin\startup.cmd -m standalone
```
#### 新增配置文件
在批量导入配置之前,请先修改`integrated-example/config/datasource-config.yaml` 中的数据源配置(用户名和密码)。
之后运行`spring-cloud-alibaba-examples/integrated-example/scripts/nacos-config-quick.sh` 来完成所有微服务配置的一键导入。
### Seata 配置
Nacos 服务注册中心以及配置中心部署完毕之后,下面是 Seata 服务端的配置。
Seata 的 db 模式需要额外配置数据库信息以及修改 Seata 服务端的配置文件,且在新版本中配置文件相较于旧版本进行了合并,因此这里为了便于演示方便,采用 Seata 单机的`file`模式启动 Seata Server。
#### 启动 Seata Server
进入到 release 解压后的 seata 目录中,执行如下命令。
```sh
#Linux/Mac环境
sh ./bin/seata-server.sh
#Win环境
bin\seata-server.bat
```
### RocketMQ 配置
Seata 服务启动后可以启动 RocketMQ 的 NameServer 以及 Broker 服务。
进入到 release 解压后的 rocketmq 目录中,执行如下命令。
#### 启动 NameServer
```sh
#Linux/Mac环境
sh bin/mqnamesrv
#Win环境
.\bin\mqnamesrv.cmd
```
#### 启动 Broker
```sh
#Linux/Mac环境
sh bin/mqbroker
#Win环境
.\bin\mqbroker.cmd
```
## 运行 Demo 示例
准备工作完成后可以运行 demo 示例,主要根据不同的使用场景,可以分别体验用户下单(分布式事务能力)以及模拟高流量点赞(熔断限流以及削峰填谷的能力)。
首先需要分别启动`integrated_frontend`以及`integrated_gateway`的工程。
- gateway 模块是整个最佳实践实例的网关。
- frontend 为最佳实践的简易前端页面。
### 分布式事务能力
#### 场景说明
针对分布式事务能力,我们提供了**用户下单购买货物的场景**,下单后:
- 先请求库存模块,扣减库存
- 扣减账户余额
- 生成订单信息返回响应
##### 启动测试
分别启动`integrated_storage`,`integrated_account`,`integrated_order`三个微服务。
访问`http://127.0.0.1:8080/order` 来体验对应场景。
直接点击下单按钮提交表单,我们模拟客户端向网关发送了一个创建订单的请求。
- 用户的 userId 为 admin
- 用户下单的商品编号为1号
- 此次订单购买的商品个数为1个
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914153234414.png)
在本 demo 示例中为了便于演示每件商品的单价都为2。
而在前面的准备工作中,**初始化业务数据库表**的时候我们新建了一个用户 userId = admin余额为 3 元;同时新建了一个编号为 1 号的商品,库存为 100 件。
因此通过上述的操作,我们会创建一个订单,扣减对应商品编号为 1 号的库存个数(100-1=99),扣减 admin 用户的余额(3-2=1)。
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914153126925.png)
如果再次请求相同的接口,同样是先扣减库存(99-1=98),但是会因为 admin 用户余额不足而抛出异常,并被 Seata 捕获,执行分布式事务二阶段提交,回滚事务。
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914153313127.png)
可以看到数据库中库存的记录因为回滚之后仍然为 99 件。
### 熔断限流,削峰填谷能力
#### 场景说明
针对大流量背景下的服务熔断限流,削峰天谷,我们提供了**用户为商品进行点赞的场景**。在此场景下,我们提供了两种应对大流量的处理方式。
- Sentinel 在网关侧绑定指定网关路由进行服务的熔断降级。
- RocketMQ 进行流量削峰填谷,在大流量请求下,生产者向 RocketMQ 发送消息,而消费者则通过可配置的消费速率进行拉取消费,减少大流量直接请求数据库增加点赞请求的压力。
#### 启动测试
分别启动`integrated_provider`以及`integrated_consumer`模块。
- Sentinel 服务熔断降级
访问`http://127.0.0.1:8080/sentinel` 体验对应场景。
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914155720469.png)
网关路由点赞服务的限流规则为 5而在前端通过异步处理模拟了 10 次并发请求。
因此可以看到 Sentinel 在 Gateway 侧针对多出的流量进行了服务熔断返回 fallback 给客户端,同时数据库的点赞数进行了更新(+5)。
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914155755103.png)
- RocketMQ 进行流量削峰填谷
访问`http://127.0.0.1:8080/rocketmq` 体验对应场景。
由于我们之前在 Nacos 中配置了`integrated-consumer`消费者模块的消费速率以及间隔,在点击按钮时我们模拟 1000 个点赞请求,针对 1000 个点赞请求,`integrated_provider`
会将 1000 次请求都向 Broker 投递消息,而在消费者模块中会根据配置的消费速率进行消费,向数据库更新点赞的商品数据,模拟大流量下 RocketMQ 削峰填谷的特性。
可以看到数据库中点赞的个数正在动态更新。
![](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220914155815191.png)
## 其他
本示例**仅是针对各个组件选取出了较为典型的功能特性来服务应用场景**
当然各个组件的功能特性不仅仅只包含最佳实践中演示的这些,如果您感兴趣或是想要深入了解,欢迎学习各个组件的独立 example 相关文档。
- Nacos Examples
- [nacos-config-example](../../nacos-example/nacos-config-example/readme-zh.md)
- [nacos-discovery-example](../../nacos-example/nacos-discovery-example/readme-zh.md)
- [Sentinel-Core-Example](../../sentinel-example/sentinel-core-example/readme-zh.md)
- [Seata Examples](../../seata-example/readme-zh.md)
- [RocketMQ Example](../../rocketmq-example/readme-zh.md)

@ -0,0 +1,85 @@
# Integrated Example
## 项目说明
本项目为 Spring Cloud Alibaba 容器化部署最佳实践的 Demo 演示项目,是整合了 Spring Cloud Alibaba 相关组件( Nacos, Sentinel, Seata, RocketMQ)的 Example 示例项目。
主要使用的组件及及其使用特性如下:
- Spring Cloud Gateway 网关
- Nacos 配置中心和服务注册中心
- Sentinel 熔断限流
- Seata 分布式事务
- RocketMQ 消息队列削峰填谷
- Docker 微服务容器化部署
- Kubernetes Helm Chart
![整体概览](https://my-img-1.oss-cn-hangzhou.aliyuncs.com/image-20220816004541921.png)
## 应用场景说明
在本 demo 示例中,我们提供了两种业务场景。
1)用户下单购买货物的场景,下单后:
- 先请求库存模块,扣减库存
- 扣减账户余额
- 生成订单信息返回响应
2)用户为商品进行点赞(模拟MQ的生产者消费者应用场景)返回商品点赞后的详细信息(点赞数等)。
### 组件详细说明
1)其中,用户下单购买货物的场景主要使用 Seata 来进行分布式事务的能力体现。
2)用户为商品进行点赞的场景,模拟大流量环境下通过 Sentinel 进行限流或是 RocketMQ 进行削峰填谷。在此场景下,我们提供了两种应对大流量的处理方式:
- Sentinel 在网关侧绑定指定网关路由进行服务的熔断降级。
- RocketMQ 进行流量削峰填谷,在大流量请求下,生产者向 RocketMQ 发送消息,而消费者则通过可配置的消费速率进行拉取消费,减少大流量直接请求数据库增加点赞请求的压力。
#### SpringCloud Gateway
微服务模块的网关。
Spring Cloud GateWay 整合 Nacos,实现动态路由配置。
通过监听 Nacos 配置的改变,实现服务网关路由配置动态刷新,每次路由信息变更,无需修改配置文件而后重启服务。
#### Nacos
各个微服务的配置中心,服务注册中心。
- 配置中心
- 共享配置MySQL 数据源相关信息配置。
- 注册中心
- 所有的微服务模块都注册到 Nacos 中进行服务注册与发现。
- 整合 SpringCloud Gateway 网关。
#### Seata
基于 Seata 的 AT 模式,用于库存模块,账户模块,订单模块的分布式事务处理。
只要库存不足/账户余额不足,回滚事务。
#### Sentinel
用于点赞场景的服务熔断限流。
整合 Nacos 配置中心与 Spring Cloud Gateway实现指定路由规则熔断限流规则动态配置。
#### RocketMQ
用于进行点赞服务流量的削峰填谷。
通过将大流量的点赞请求从生产者发送到mq消费者模块从mq中拉取进行一定频率的消费不是简单的直接服务熔断限流降级实现 RocketMQ 针对大流量的削峰填谷能力。
## 版本说明
本项目提供了[本地部署运行版本](local-deployment-zh.md)以及[Kubernetes Helm-Chart 版本](kubernetes-deployment-zh.md)。
- 如果想要了解具体如何配置各项组件以及完整环境搭建,推荐学习[本地部署运行版本](local-deployment-zh.md)。
- 如果想要在K8S集群上快速体验组件效果跳过各个组件环境部署等过程请查看[Kubernetes Helm-Chart 版本](kubernetes-deployment-zh.md)。

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integrated-account</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>integrated-common</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,32 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author TrevorLink
*/
@SpringBootApplication
public class AccountServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AccountServiceApplication.class, args);
}
}

@ -0,0 +1,57 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.controller;
import com.alibaba.cloud.integration.account.dto.AccountDTO;
import com.alibaba.cloud.integration.account.service.AccountService;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@PostMapping("/reduce-balance")
public Result<?> reduceBalance(@RequestBody AccountDTO accountDTO) {
try {
accountService.reduceBalance(accountDTO.getUserId(), accountDTO.getPrice());
}
catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return Result.success("");
}
@GetMapping("/")
public Result<?> getRemainAccount(String userId) {
return accountService.getRemainAccount(userId);
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.dto;
/**
* @author TrevorLink
*/
public class AccountDTO {
private String userId;
private Integer price;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}

@ -0,0 +1,42 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.mapper;
import java.sql.Timestamp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface AccountMapper {
@Select("SELECT money FROM account WHERE user_id = #{userId}")
Integer getBalance(@Param("userId") String userId);
@Update("UPDATE account SET money = money - #{price},update_time = #{updateTime} WHERE user_id = #{userId} AND money >= ${price}")
int reduceBalance(@Param("userId") String userId, @Param("price") Integer price,
@Param("updateTime") Timestamp updateTime);
}

@ -0,0 +1,31 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.service;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
/**
* @author TrevorLink
*/
public interface AccountService {
void reduceBalance(String userId, Integer price) throws BusinessException;
Result<?> getRemainAccount(String userId);
}

@ -0,0 +1,74 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.account.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.account.mapper.AccountMapper;
import com.alibaba.cloud.integration.account.service.AccountService;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import io.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author TrevorLink
*/
@Service
public class AccountServiceImpl implements AccountService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private AccountMapper accountMapper;
@Override
@Transactional
public void reduceBalance(String userId, Integer price) throws BusinessException {
logger.info("[reduceBalance] currenet XID: {}", RootContext.getXID());
checkBalance(userId, price);
Timestamp updateTime = new Timestamp(System.currentTimeMillis());
int updateCount = accountMapper.reduceBalance(userId, price, updateTime);
if (updateCount == 0) {
throw new BusinessException("reduce balance failed");
}
}
@Override
public Result<?> getRemainAccount(String userId) {
Integer balance = accountMapper.getBalance(userId);
if (balance == null) {
return Result.failed("wrong userId,please check the userId");
}
return Result.success(balance);
}
private void checkBalance(String userId, Integer price) throws BusinessException {
Integer balance = accountMapper.getBalance(userId);
if (balance < price) {
throw new BusinessException("no enough balance");
}
}
}

@ -0,0 +1,24 @@
server:
port: 8012
spring:
application:
name: integrated-account
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
group: integrated-example
shared-dataids: datasorce-config.yaml
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
integrated-account-group: default
grouplist:
default: localhost:8091

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integrated-common</artifactId>
</project>

@ -0,0 +1,28 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
/**
* @author TrevorLink
*/
public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message);
}
}

@ -0,0 +1,33 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
public interface IResult {
/**
* Get result code.
* @return result code
*/
Integer getCode();
/**
* Get result message.
* @return result message
*/
String getMessage();
}

@ -0,0 +1,93 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
/**
* @author TrevorLink
*/
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(),
data);
}
public static <T> Result<T> success(String message, T data) {
return new Result<>(ResultEnum.SUCCESS.getCode(), message, data);
}
public static Result<?> failed() {
return new Result<>(ResultEnum.COMMON_FAILED.getCode(),
ResultEnum.COMMON_FAILED.getMessage(), null);
}
public static Result<?> failed(String message) {
return new Result<>(ResultEnum.COMMON_FAILED.getCode(), message, null);
}
public static Result<?> failed(IResult errorResult) {
return new Result<>(errorResult.getCode(), errorResult.getMessage(), null);
}
public Result() {
}
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static <T> Result<T> instance(Integer code, String message, T data) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
result.setData(data);
return result;
}
}

@ -0,0 +1,64 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.common;
/**
* Integrated Example common result enum class.
* @author TrevorLink
*/
public enum ResultEnum implements IResult {
/**
* return success result.
*/
SUCCESS(2001, "接口调用成功"),
/**
* return business common failed.
*/
COMMON_FAILED(2003, "接口调用失败");
private Integer code;
private String message;
ResultEnum() {
}
ResultEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
@Override
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>integrated-frontend</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,33 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.frontend;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author HuangSir
* @date 2022-09-08 14:11
*/
@SpringBootApplication
public class FrontendApplication {
public static void main(String[] args) {
SpringApplication.run(FrontendApplication.class, args);
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.frontend.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author HuangSir
* @date 2022-09-08 14:00
*/
@Controller
public class IntegrationController {
@RequestMapping("/order")
public String order() {
return "order";
}
@RequestMapping("/rocketmq")
public String rocketmq() {
return "rocketmq";
}
@RequestMapping("/sentinel")
public String sentinel() {
return "sentinel";
}
}

@ -0,0 +1,91 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title></title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body th:style="${'background-color:' + backgroundColor }">
<div style="margin: 30px auto 0 30px;">
<div id="orderSection">
<label>商品下单场景:</label>
<form id="orderForm">
<div>
<label>用户ID</label>
<input type="text" id="userId" name="userId" value="admin"/>
</div>
<div>
<label>商品编号</label>
<input type="text" id="commodityCode" name="commodityCode" value="1"/>
</div>
<div>
<label>商品个数</label>
<input type="number" name="count" value="1"/>
</div>
<button type="button" class="btnStart">提交</button>
</form>
</div>
<div id="orderResultSection" style="margin-top: 30px; border-top: 1px solid #eaeaea;">
</div>
</div>
<script charset="utf-8">
$(".btnStart").click(function () {
$('#orderResultSection').empty();
var userId = $("#userId").val();
var commodityCode = $("#commodityCode").val();
$.ajax({
url: "http://localhost:8010/storage/",
type: "get",
dataType: "json",
data: "commodityCode=" + commodityCode,
async:false,
success: function (res) {
$('#orderResultSection').append(`<p> 执行分布式业务前商品库存: ${res.data} </p>`);
}
});
$.ajax({
url: "http://localhost:8010/account/",
type: "get",
dataType: "json",
data: "userId=" + userId,
async:false,
success: function (res) {
$('#orderResultSection').append(`<p> 执行分布式业务前账户余额: ${res.data}</p>`);
}
});
$.ajax({
type: "POST",
url: "http://localhost:8010/order/create",
data: $('#orderForm').serialize(),
dataType: 'json',
async:false,
success: function (res) {
$('#orderResultSection').append(`<p> ${res.message} </p>`);
$.ajax({
url: "http://localhost:8010/storage/",
type: "get",
dataType: "json",
data: "commodityCode=" + commodityCode,
async:false,
success: function (res) {
$('#orderResultSection').append(`<p> 执行分布式业务后商品库存: ${res.data}</p>`);
}
});
$.ajax({
url: "http://localhost:8010/account/",
type: "get",
dataType: "json",
data: "userId=" + userId,
async:false,
success: function (res) {
$('#orderResultSection').append(`<p> 执行分布式业务后账户余额: ${res.data}</p>`);
}
});
}
});
});
</script>
</body>
</html>

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title></title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body th:style="${'background-color:' + backgroundColor }">
<div style="margin: 30px auto 0 30px;">
<div id="RocketMQSection">
<label>RocketMQ 削峰填谷场景:</label>
<br>
<label>被点赞的商品ID</label>
<input id="itemId" style="width: 200px;height: 20px;" value="1">
<br>
<button class="btnStart">开始调用</button>
</div>
<div id="rocketmqResultSection" style="margin-top: 30px; border-top: 1px solid #eaeaea;">
</div>
</div>
<script charset="utf-8">
var count = 0;
window.onload = function () {
const timeId = setInterval(function () {
if (count == 1000) {
console.log("终止轮询")
clearInterval(timeId)
}
queryRes()
}, 500)
function queryRes() {
$.ajax({
url: "http://localhost:8010/praise/query",
type: "get",
dataType: "json",
data: "itemId=" + $('#itemId').val(),
success: function (res) {
console.log("准备查询此时count=" + count)
$('#rocketmqResultSection').append(`<p> 点赞数: ${res} </p>`);
}
})
}
}
$('.btnStart').click(() => {
var itemId = $('#itemId').val();
$('#rocketmqResultSection').empty();
for (let i = 0; i < 1000; i++) {
$.ajax({
url: "http://localhost:8010/praise/rocketmq",
type: "get",
dataType: "json",
data: "itemId=" + itemId,
success: function () {
console.log("点赞成功更新count")
count++;
}
});
}
});
const getDateTime = () => {
const myDate = new Date;
const year = myDate.getFullYear();
const month = myDate.getMonth() + 1;
const date = myDate.getDate();
const hours = myDate.getHours();
const minutes = myDate.getMinutes();
const seconds = myDate.getSeconds();
return `${year}-${month}-${date} ${hours}:${minutes}:${seconds}`;
};
</script>
</body>
</html>

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title></title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body th:style="${'background-color:' + backgroundColor }">
<div style="margin: 30px auto 0 30px;">
<div id="SentinelSection">
<label>Sentinel 限流降级场景:</label>
<br>
<label>被点赞的商品ID</label>
<input id="itemId" style="width: 200px;height: 20px;" value="1">
<br>
<button class="btnStart">开始调用</button>
</div>
<div id="sentinelResultSection" style="margin-top: 30px; border-top: 1px solid #eaeaea;">
</div>
</div>
<script charset="utf-8">
$('.btnStart').click(() => {
$('#sentinelResultSection').empty();
var itemId = $('#itemId').val();
$.ajax({
url: "http://localhost:8010/praise/query",
type: "get",
dataType: "json",
data: "itemId=" + itemId,
async: false,
success: function (res) {
$('#sentinelResultSection').append(`<p> 点赞前的点赞数: ${res} </p>`);
}
});
for (let i = 0; i < 10; i++) {
$.ajax({
url: "http://localhost:8010/praise/sentinel",
type: "get",
dataType: "json",
data: "itemId=" + itemId,
success: function (res) {
console.log(res)
$('#sentinelResultSection').append(`<p> ${getDateTime()}: ${res}</p>`);
},
error: function (res) {
console.log(res)
$('#sentinelResultSection').append(`<p> ${getDateTime()}: 请求失败,接口被限流 </p>`);
}
});
}
timeoutid = setTimeout(queryRes, 1000);
function queryRes() {
$.ajax({
url: "http://localhost:8010/praise/query",
type: "get",
dataType: "json",
data: "itemId=" + $('#itemId').val(),
success: function (res) {
$('#sentinelResultSection').append(`<p> 点赞后的点赞数: ${res} </p>`);
}
})
}
});
const getDateTime = () => {
const myDate = new Date;
const year = myDate.getFullYear(); //获取当前年
const month = myDate.getMonth() + 1; //获取当前月
const date = myDate.getDate(); //获取当前日
const hours = myDate.getHours();
const minutes = myDate.getMinutes();
const seconds = myDate.getSeconds();
return `${year}-${month}-${date} ${hours}:${minutes}:${seconds}`;
};
</script>
</body>
</html>

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integrated-gateway</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,34 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author TrevorLink
*/
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}

@ -0,0 +1,116 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.gateway.config;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
/**
* @author TrevorLink
*/
@Configuration
public class GatewayConfig {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(
new GatewayFlowRule("praiseItemSentinel").setCount(5).setIntervalSec(1));
GatewayRuleManager.loadRules(rules);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers,
serverCodecConfigurer);
}
@PostConstruct
public void initBlockHandlers() {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange,
Throwable throwable) {
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject("此接口被限流了"));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
@Bean
public CorsWebFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}

@ -0,0 +1,13 @@
server:
port: 8010
spring:
application:
name: integrated-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
group: integrated-example

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integrated-order</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>integrated-common</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,34 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author TrevorLink
*/
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}

@ -0,0 +1,53 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.controller;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
public Result<?> createOrder(@RequestParam("userId") String userId,
@RequestParam("commodityCode") String commodityCode,
@RequestParam("count") Integer count) {
Result<?> res = null;
try {
res = orderService.createOrder(userId, commodityCode, count);
}
catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return res;
}
}

@ -0,0 +1,103 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.entity;
import java.sql.Timestamp;
/**
* @author TrevorLink
*/
public class Order {
private Integer id;
private String userId;
private String commodityCode;
private Integer count;
private Integer money;
private Timestamp createTime;
private Timestamp updateTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getCommodityCode() {
return commodityCode;
}
public void setCommodityCode(String commodityCode) {
this.commodityCode = commodityCode;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
public Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
public Timestamp getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Timestamp updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ commodityCode + '\'' + ", count=" + count + ", money=" + money
+ ", createTime=" + createTime + ", updateTime=" + updateTime + '}';
}
}

@ -0,0 +1,35 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.feign.dto.AccountDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* @author TrevorLink
*/
@FeignClient(name = "integrated-account")
public interface AccountServiceFeignClient {
@PostMapping("/account/reduce-balance")
Result<?> reduceBalance(@RequestBody AccountDTO accountReduceBalanceDTO);
}

@ -0,0 +1,35 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.feign.dto.StorageDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* @author TrevorLink
*/
@FeignClient(name = "integrated-storage")
public interface StorageServiceFeignClient {
@PostMapping("/storage/reduce-stock")
Result<?> reduceStock(@RequestBody StorageDTO productReduceStockDTO);
}

@ -0,0 +1,44 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign.dto;
/**
* @author TrevorLink
*/
public class AccountDTO {
private String userId;
private Integer price;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.feign.dto;
/**
* @author TrevorLink
*/
public class StorageDTO {
private String commodityCode;
private Integer count;
public String getCommodityCode() {
return commodityCode;
}
public void setCommodityCode(String commodityCode) {
this.commodityCode = commodityCode;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}

@ -0,0 +1,37 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.mapper;
import com.alibaba.cloud.integration.order.entity.Order;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface OrderMapper {
@Insert("INSERT INTO `order` (user_id, commodity_code,money,create_time,update_time) VALUES (#{userId}, #{commodityCode},#{money},#{createTime},#{updateTime})")
@Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
int saveOrder(Order order);
}

@ -0,0 +1,30 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.service;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
/**
* @author TrevorLink
*/
public interface OrderService {
Result<?> createOrder(String userId, String commodityCode, Integer count)
throws BusinessException;
}

@ -0,0 +1,96 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.order.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.order.entity.Order;
import com.alibaba.cloud.integration.order.feign.AccountServiceFeignClient;
import com.alibaba.cloud.integration.order.feign.StorageServiceFeignClient;
import com.alibaba.cloud.integration.order.feign.dto.AccountDTO;
import com.alibaba.cloud.integration.order.feign.dto.StorageDTO;
import com.alibaba.cloud.integration.order.mapper.OrderMapper;
import com.alibaba.cloud.integration.order.service.OrderService;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import static com.alibaba.cloud.integration.common.ResultEnum.COMMON_FAILED;
/**
* @author TrevorLink
*/
@Service
public class OrderServiceImpl implements OrderService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private OrderMapper orderMapper;
@Autowired
private AccountServiceFeignClient accountService;
@Autowired
private StorageServiceFeignClient storageService;
@Override
@GlobalTransactional
public Result<?> createOrder(String userId, String commodityCode, Integer count) {
logger.info("[createOrder] current XID: {}", RootContext.getXID());
// deduct storage
StorageDTO storageDTO = new StorageDTO();
storageDTO.setCommodityCode(commodityCode);
storageDTO.setCount(count);
Integer storageCode = storageService.reduceStock(storageDTO).getCode();
if (storageCode.equals(COMMON_FAILED.getCode())) {
throw new BusinessException("stock not enough");
}
// deduct balance
int price = count * 2;
AccountDTO accountDTO = new AccountDTO();
accountDTO.setUserId(userId);
accountDTO.setPrice(price);
Integer accountCode = accountService.reduceBalance(accountDTO).getCode();
if (accountCode.equals(COMMON_FAILED.getCode())) {
throw new BusinessException("balance not enough");
}
// save order
Order order = new Order();
order.setUserId(userId);
order.setCommodityCode(commodityCode);
order.setCount(count);
order.setMoney(price);
order.setCreateTime(new Timestamp(System.currentTimeMillis()));
order.setUpdateTime(new Timestamp(System.currentTimeMillis()));
orderMapper.saveOrder(order);
logger.info("[createOrder] orderId: {}", order.getId());
return Result.success(order);
}
}

@ -0,0 +1,24 @@
server:
port: 8013
spring:
application:
name: integrated-order
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
group: integrated-example
shared-dataids: datasorce-config.yaml
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
integrated-order-group: default
grouplist:
default: localhost:8091

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integrated-praise-consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,36 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer;
import com.alibaba.cloud.integration.consumer.message.PraiseSink;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
/**
* @author TrevorLink
*/
@SpringBootApplication
@EnableBinding(PraiseSink.class)
public class PraiseConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(PraiseConsumerApplication.class, args);
}
}

@ -0,0 +1,41 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.controller;
import com.alibaba.cloud.integration.consumer.service.PraiseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/praise")
public class PraiseController {
@Autowired
private PraiseService praiseService;
@GetMapping("/query")
public Integer getPraise(Integer itemId) {
return praiseService.getPraise(itemId);
}
}

@ -0,0 +1,42 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.listener;
import com.alibaba.cloud.integration.consumer.message.PraiseMessage;
import com.alibaba.cloud.integration.consumer.message.PraiseSink;
import com.alibaba.cloud.integration.consumer.service.PraiseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
/**
* @author TrevorLink
*/
@Component
public class PraiseConsumer {
@Autowired
private PraiseService praiseService;
@StreamListener(PraiseSink.PRAISE_INPUT)
public void onMessage(@Payload PraiseMessage message) {
praiseService.praiseItem(message.getItemId());
}
}

@ -0,0 +1,42 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.mapper;
import java.sql.Timestamp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface PraiseMapper {
@Update("update item set praise = praise+1,update_time=#{updateTime} where id = #{itemId}")
int praiseItem(@Param("itemId") Integer itemId,
@Param("updateTime") Timestamp updateTime);
@Select("select praise from item where id = #{itemId}")
int getPraise(@Param("itemId") Integer itemId);
}

@ -0,0 +1,39 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.message;
/**
* @author TrevorLink
*/
public class PraiseMessage {
private Integer itemId;
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
@Override
public String toString() {
return "PraiseMessage{" + "itemId=" + itemId + '}';
}
}

@ -0,0 +1,35 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.message;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
/**
* @author TrevorLink
*/
public interface PraiseSink {
/**
* rocketmq input name.
*/
String PRAISE_INPUT = "praise-input";
@Input(PRAISE_INPUT)
SubscribableChannel praiseInput();
}

@ -0,0 +1,28 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.service;
/**
* @author TrevorLink
*/
public interface PraiseService {
void praiseItem(Integer itemId);
int getPraise(Integer itemId);
}

@ -0,0 +1,47 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.consumer.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.consumer.mapper.PraiseMapper;
import com.alibaba.cloud.integration.consumer.service.PraiseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author TrevorLink
*/
@Service
public class PraiseServiceImpl implements PraiseService {
@Autowired
private PraiseMapper praiseMapper;
@Override
public void praiseItem(Integer itemId) {
Timestamp updateTime = new Timestamp(System.currentTimeMillis());
praiseMapper.praiseItem(itemId, updateTime);
}
@Override
public int getPraise(Integer itemId) {
return praiseMapper.getPraise(itemId);
}
}

@ -0,0 +1,15 @@
spring:
application:
name: integrated-consumer
cloud:
nacos:
config:
file-extension: yaml
server-addr: localhost:8848
shared-configs[0]:
dataId: datasorce-config.yaml
group: integrated-example
discovery:
server-addr: localhost:8848
server:
port: 8014

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integrated-praise-provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,36 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.provider;
import com.alibaba.cloud.integration.provider.message.PraiseSource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
/**
* @author TrevorLink
*/
@SpringBootApplication
@EnableBinding(PraiseSource.class)
public class PraiseProviderApplication {
public static void main(String[] args) {
SpringApplication.run(PraiseProviderApplication.class, args);
}
}

@ -0,0 +1,49 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.provider.controller;
import com.alibaba.cloud.integration.provider.message.PraiseMessage;
import com.alibaba.cloud.integration.provider.message.PraiseSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/praise")
public class PraiseController {
@Autowired
private PraiseSource praiseSource;
@GetMapping({ "/rocketmq", "/sentinel" })
public boolean praise(@RequestParam Integer itemId) {
PraiseMessage message = new PraiseMessage();
message.setItemId(itemId);
Message<PraiseMessage> praiseMessage = MessageBuilder.withPayload(message)
.build();
return praiseSource.praiseOutput().send(praiseMessage);
}
}

@ -0,0 +1,39 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.provider.message;
/**
* @author TrevorLink
*/
public class PraiseMessage {
private Integer itemId;
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
@Override
public String toString() {
return "PraiseMessage{" + "itemId=" + itemId + '}';
}
}

@ -0,0 +1,30 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.provider.message;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
/**
* @author TrevorLink
*/
public interface PraiseSource {
@Output("praise-output")
MessageChannel praiseOutput();
}

@ -0,0 +1,11 @@
spring:
application:
name: integrated-provider
cloud:
nacos:
config:
file-extension: yaml
server-addr: localhost:8848
group: integrated-example
server:
port: 8015

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integrated-storage</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>integrated-common</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,32 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author TrevorLink
*/
@SpringBootApplication
public class StorageServiceApplication {
public static void main(String[] args) {
SpringApplication.run(StorageServiceApplication.class, args);
}
}

@ -0,0 +1,58 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.controller;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.storage.dto.StorageDTO;
import com.alibaba.cloud.integration.storage.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author TrevorLink
*/
@RestController
@RequestMapping("/storage")
public class StorageController {
@Autowired
private StorageService storageService;
@PostMapping("/reduce-stock")
public Result<?> reduceStock(@RequestBody StorageDTO storageDTO) {
try {
storageService.reduceStock(storageDTO.getCommodityCode(),
storageDTO.getCount());
}
catch (BusinessException e) {
return Result.failed(e.getMessage());
}
return Result.success("");
}
@GetMapping("/")
public Result<?> getRemainCount(String commodityCode) {
return storageService.getRemainCount(commodityCode);
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.dto;
/**
* @author TrevorLink
*/
public class StorageDTO {
private String commodityCode;
private Integer count;
public String getCommodityCode() {
return commodityCode;
}
public void setCommodityCode(String commodityCode) {
this.commodityCode = commodityCode;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}

@ -0,0 +1,42 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.mapper;
import java.sql.Timestamp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
/**
* @author TrevorLink
*/
@Mapper
@Repository
public interface StorageMapper {
@Select("SELECT `count` FROM storage WHERE commodity_code = #{commodityCode}")
Integer getStock(@Param("commodityCode") String commodityCode);
@Update("UPDATE storage SET count = count - #{count},update_time=#{updateTime} WHERE commodity_code = #{commodityCode}")
int reduceStock(@Param("commodityCode") String commodityCode,
@Param("count") Integer count, @Param("updateTime") Timestamp updateTime);
}

@ -0,0 +1,31 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.service;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
/**
* @author TrevorLink
*/
public interface StorageService {
void reduceStock(String commodityCode, Integer orderCount) throws BusinessException;
Result<?> getRemainCount(String commodityCode);
}

@ -0,0 +1,76 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.integration.storage.service.impl;
import java.sql.Timestamp;
import com.alibaba.cloud.integration.common.BusinessException;
import com.alibaba.cloud.integration.common.Result;
import com.alibaba.cloud.integration.storage.mapper.StorageMapper;
import com.alibaba.cloud.integration.storage.service.StorageService;
import io.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author TrevorLink
*/
@Service
public class StorageServiceImpl implements StorageService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private StorageMapper storageMapper;
@Override
@Transactional
public void reduceStock(String commodityCode, Integer count)
throws BusinessException {
logger.info("[reduceStock] current XID: {}", RootContext.getXID());
checkStock(commodityCode, count);
Timestamp updateTime = new Timestamp(System.currentTimeMillis());
int updateCount = storageMapper.reduceStock(commodityCode, count, updateTime);
if (updateCount == 0) {
throw new BusinessException("deduct stock failed");
}
}
@Override
public Result<?> getRemainCount(String commodityCode) {
Integer stock = storageMapper.getStock(commodityCode);
if (stock == null) {
return Result.failed("commodityCode wrong,please check commodity code");
}
return Result.success(stock);
}
private void checkStock(String commodityCode, Integer count)
throws BusinessException {
Integer stock = storageMapper.getStock(commodityCode);
if (stock < count) {
throw new BusinessException("no enough stock");
}
}
}

@ -0,0 +1,24 @@
server:
port: 8011
spring:
application:
name: integrated-storage
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
group: integrated-example
shared-dataids: datasorce-config.yaml
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
integrated-storage-group: default
grouplist:
default: localhost:8091

@ -0,0 +1,18 @@
#!/bin/sh
groupId="integrated-example"
echo "Nacos auto config started"
datasourceConfig=$(cat ../config/datasource-config.yaml)
storageConfig=$(cat ../config/integrated-storage.yaml)
accountConfig=$(cat ../config/integrated-account.yaml)
orderConfig=$(cat ../config/integrated-order.yaml)
gatewayConfig=$(cat ../config/integrated-gateway.yaml)
providerConfig=$(cat ../config/integrated-provider.yaml)
consumerConfig=$(cat ../config/integrated-consumer.yaml)
curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" -d "dataId=datasource-config.yaml&group=${groupId}&content=${datasourceConfig}"
curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" -d "dataId=integrated-storage.yaml&group=${groupId}&content=${storageConfig}"
curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" -d "dataId=integrated-account.yaml&group=${groupId}&content=${accountConfig}"
curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" -d "dataId=integrated-order.yaml&group=${groupId}&content=${orderConfig}"
curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" -d "dataId=integrated-gateway.yaml&group=${groupId}&content=${gatewayConfig}"
curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" -d "dataId=integrated-provider.yaml&group=${groupId}&content=${providerConfig}"
curl -X POST "127.0.0.1:8848/nacos/v1/cs/configs" -d "dataId=integrated-consumer.yaml&group=${groupId}&content=${consumerConfig}"
echo "Nacos config pushed successfully finished"

@ -0,0 +1,121 @@
-- Storage库存微服务的数据库业务初始化
DROP DATABASE IF EXISTS integrated_storage;
CREATE DATABASE integrated_storage;
USE integrated_storage;
CREATE TABLE `storage`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARSET = utf8;
INSERT INTO `storage`
VALUES ('1', '1', '100', '2022-08-07 22:48:29', '2022-08-14 13:49:05');
-- Account账户微服务的数据库业务初始化
DROP DATABASE IF EXISTS integrated_account;
CREATE DATABASE integrated_account;
USE integrated_account;
CREATE TABLE `account`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARSET = utf8;
INSERT INTO `account`
VALUES ('1', 'admin', '3', '2022-08-07 22:53:01', '2022-08-14 13:49:05');
-- Order订单微服务的数据库业务初始化
DROP DATABASE IF EXISTS integrated_order;
CREATE DATABASE integrated_order;
USE integrated_order;
CREATE TABLE `order`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
`money` int(11) DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 16
DEFAULT CHARSET = utf8;
-- 点赞业务的数据库初始化
DROP DATABASE IF EXISTS integrated_praise;
CREATE DATABASE integrated_praise;
USE integrated_praise;
CREATE TABLE `item`
(
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`praise` int(11) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARSET = utf8;
INSERT INTO `item`
VALUES ('1', '0', '2022-08-14 00:33:50', '2022-08-14 14:07:34');
-- Storage库存微服务的数据库Seata初始化
USE integrated_storage;
CREATE TABLE `undo_log`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- Storage库存微服务的数据库Seata初始化
USE integrated_account;
CREATE TABLE `undo_log`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- Storage库存微服务的数据库Seata初始化
USE integrated_order;
CREATE TABLE `undo_log`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;

@ -45,7 +45,15 @@
<module>spring-cloud-bus-rocketmq-example</module>
<module>spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-example</module>
<module>spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-consul-example</module>
</modules>
<module>integrated-example/integrated-storage</module>
<module>integrated-example/integrated-account</module>
<module>integrated-example/integrated-order</module>
<module>integrated-example/integrated-gateway</module>
<module>integrated-example/integrated-praise-provider</module>
<module>integrated-example/integrated-praise-consumer</module>
<module>integrated-example/integrated-common</module>
<module>integrated-example/integrated-frontend</module>
</modules>
<build>
<plugins>

Loading…
Cancel
Save