diff --git a/README.md b/README.md index dc3dfc0..5424e7a 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,98 @@ >转载请标明出处: -> https://blog.csdn.net/u010562966/article/details/88995076 -> 本文出自[程序员果果的博客](https://blog.csdn.net/u010562966) -> +> http://blog.itwolfed.com/ +> 本文出自[程序员果果的博客](http://blog.itwolfed.com/) ### 源码 - github | Spring Boot 系列 :[https://github.com/gf-huanchupk/SpringBootLearning](https://github.com/gf-huanchupk/SpringBootLearning),记得star哦! - github | Spring Cloud 系列 :[https://github.com/gf-huanchupk/SpringCloudLearning](https://github.com/gf-huanchupk/SpringCloudLearning),记得star哦! +### RocketMQ 系列 +- [RocketMQ 教程 | RocketMQ 简介](http://blog.itwolfed.com/blog/98) +- [RocketMQ 教程 | RocketMQ 安装](http://blog.itwolfed.com/blog/99) +- [RocketMQ 教程 | RocketMQ 常用消息类型](http://blog.itwolfed.com/blog/101) ### Spring Boot 系列 -- [Spring Boot 教程 | Spring Boot 自定义 starter](https://mp.weixin.qq.com/s/F_1j-ng49QNlbj04Q9bqFQ) -- [Spring Boot 教程 | Spring Boot 整合 mybatis-plus](https://mp.weixin.qq.com/s/ITZIPCttey-iYCyhIa8uSw) -- [Spring Boot 教程 | Spring Boot 整合 spring cache](https://mp.weixin.qq.com/s/nqozEsvl5ZMaREMv2gZKlQ) -- [Spring Boot 教程 | Spring Boot 整合 rabbitmq](https://mp.weixin.qq.com/s/ZhP8zF3GyiIm0fPiTDLWxA) -- [Spring Boot 教程 | Spring Boot 整合 elasticsearch](https://mp.weixin.qq.com/s/f9eE7jsPNWAr1gQ0iF-kDw) -- [Spring Boot 教程 | Spring Boot 整合 docker](https://mp.weixin.qq.com/s/IWDpC9i8P3ZDFDYTsKARag) -- [Spring Boot 教程 | Spring Boot 整合 elk](https://mp.weixin.qq.com/s/k6UUCD-Rn96po2dw6maSxQ) -- [Spring Boot 教程 | Spring Boot Admin 2.0 详解](https://mp.weixin.qq.com/s/JSJH32N_bCzaWjZTubUDTA) -- [Spring Boot 教程 | Spring Boot 整合 apollo](https://mp.weixin.qq.com/s/8UR13rTY2elAGedfFC8EiQ) -- [Spring Boot 教程 | Spring Boot Security 详解](https://mp.weixin.qq.com/s/bSWs_3wIavdhHayDtKHpUg) -- [Spring Boot 教程 | Spring Boot Security 整合 OAuth2 设计安全API接口服务](https://mp.weixin.qq.com/s/0PAUErDh0qmcR4SUsTn15Q) -- [Spring Boot 教程 | Spring Boot Security 整合 JWT 实现 无状态的分布式API接口](https://mp.weixin.qq.com/s/QO5L1-RCR-jmIuHlZIfkqQ) +- [Spring Boot 教程 | Spring Boot 自定义 starter](http://blog.itwolfed.com/blog/5) +- [Spring Boot 教程 | Spring Boot 整合 mybatis-plus](http://blog.itwolfed.com/blog/6) +- [Spring Boot 教程 | Spring Boot 整合 spring cache](http://blog.itwolfed.com/blog/7) +- [Spring Boot 教程 | Spring Boot 整合 rabbitmq](http://blog.itwolfed.com/blog/8) +- [Spring Boot 教程 | Spring Boot 整合 elasticsearch](http://blog.itwolfed.com/blog/9) +- [Spring Boot 教程 | Spring Boot 整合 docker](http://blog.itwolfed.com/blog/10) +- [Spring Boot 教程 | Spring Boot 整合 elk](http://blog.itwolfed.com/blog/11) +- [Spring Boot 教程 | Spring Boot Admin 2.0 详解](http://blog.itwolfed.com/blog/12) +- [Spring Boot 教程 | Spring Boot 整合 apollo](http://blog.itwolfed.com/blog/13) +- [Spring Boot 教程 | Spring Boot Security 详解](http://blog.itwolfed.com/blog/14) +- [Spring Boot 教程 | Spring Boot Security 整合 OAuth2 设计安全API接口服务](http://blog.itwolfed.com/blog/15) +- [Spring Boot 教程 | Spring Boot Security 整合 JWT 实现 无状态的分布式API接口](http://blog.itwolfed.com/blog/16) +- [Spring Boot 教程 | Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器](http://blog.itwolfed.com/blog/17) +- [Spring Boot 教程 | Spring Boot Actuator 整合 Prometheus](http://blog.itwolfed.com/blog/18) +- [Spring Boot 教程 | Spring Boot 集成 Seata 解决分布式事务问题](http://blog.itwolfed.com/blog/19) +- [Spring Boot 教程 | Spring Boot 使用 JSR303 实现参数验证](http://blog.itwolfed.com/blog/97) ### Spring Cloud 系列 -- [第一篇 : 服务的注册与发现(Eureka)](https://mp.weixin.qq.com/s/Ahg6Z5PL9UAhaKSQjUOg3g) -- [第二篇 : 服务消费者(rest+ribbon)](https://mp.weixin.qq.com/s/LanJnx04KaAuSkeomaE5Uw) -- [第三篇 : 服务消费者(Feign)](https://mp.weixin.qq.com/s/2_OxTx1_6PfQx3z7baxocw) -- [第四篇 : 断路器(Hystrix)](https://mp.weixin.qq.com/s/XhjHZ9fD2s34Eb665O6npQ) -- [第五篇 : 路由网关(Zuul)](https://mp.weixin.qq.com/s/GYu_BRxuhmGl7dQnlnsEmQ) -- [第六篇 : 分布式配置中心(Spring Cloud Config)](https://mp.weixin.qq.com/s/Pbcc3B3vzrMUKgbpijrJFQ) -- [第七篇 : 高可用的分布式配置中心(Spring Cloud Config)](https://mp.weixin.qq.com/s/yj0snlPFobakq3akc_FJGw) -- [第八篇 : 消息总线(Spring Cloud Bus) 8 months ago](https://mp.weixin.qq.com/s/a2NLClc56BXJxrIiCXODUw) -- [第九篇 : 服务链路追踪(Spring Cloud Sleuth)](https://mp.weixin.qq.com/s/a2NLClc56BXJxrIiCXODUw) -- [第十篇 : 高可用的服务注册中心](https://mp.weixin.qq.com/s/A75d2Ec5-IwoGxbJEWj41w) -- [第十一篇 : 断路器监控(Hystrix Dashboard)](https://mp.weixin.qq.com/s/Sv7agttPg2R1kyXMvxI-Gw) -- [第十二篇 : 断路器聚合监控(Hystrix Turbine)](https://mp.weixin.qq.com/s/KyAdC-k_r9ldyozKmnyK3Q) -- [第十三篇 : 路由网关(Gateway)](https://mp.weixin.qq.com/s/2twx-aCEM2GXluDUIubGZg) -- [第十四篇 : 调用链监控 CAT 之 入门](https://mp.weixin.qq.com/s/G15cw9yXpq4cOFB2C29JYw) -- [第十五篇 : 调用链监控 CAT 之 URL埋点实践](https://mp.weixin.qq.com/s/0tLjjlUtKTyOlH-5elj0Xw) -- [第十六篇 : 微服务容错限流Hystrix入门](https://mp.weixin.qq.com/s/G15cw9yXpq4cOFB2C29JYw) -- [第十七篇 : 微服务容错限流Hystrix之Dashboard](https://mp.weixin.qq.com/s/Nmqu2ul4aRT6iXecxrmt9A) -- [第十八篇 : 微服务容错限流Hystrix之流聚合](https://mp.weixin.qq.com/s/2RNK2XkjTvd1sUM7oR-Jfw) +- [第一篇 : 服务的注册与发现(Eureka)](http://blog.itwolfed.com/blog/20) +- [第二篇 : 服务消费者(rest+ribbon)](http://blog.itwolfed.com/blog/21) +- [第三篇 : 服务消费者(Feign)](http://blog.itwolfed.com/blog/22) +- [第四篇 : 断路器(Hystrix)](http://blog.itwolfed.com/blog/23) +- [第五篇 : 路由网关(Zuul)](http://blog.itwolfed.com/blog/24) +- [第六篇 : 分布式配置中心(Spring Cloud Config)](http://blog.itwolfed.com/blog/25) +- [第七篇 : 高可用的分布式配置中心(Spring Cloud Config)](http://blog.itwolfed.com/blog/26) +- [第八篇 : 消息总线(Spring Cloud Bus)](http://blog.itwolfed.com/blog/27) +- [第九篇 : 服务链路追踪(Spring Cloud Sleuth)](http://blog.itwolfed.com/blog/28) +- [第十篇 : 高可用的服务注册中心](http://blog.itwolfed.com/blog/29) +- [第十一篇 : 断路器监控(Hystrix Dashboard)](http://blog.itwolfed.com/blog/30) +- [第十二篇 : 断路器聚合监控(Hystrix Turbine)](http://blog.itwolfed.com/blog/31) +- [第十三篇 : 路由网关(Gateway)](http://blog.itwolfed.com/blog/32) +- [第十四篇 : 调用链监控 CAT 之 入门](http://blog.itwolfed.com/blog/37) +- [第十五篇 : 调用链监控 CAT 之 URL埋点实践](http://blog.itwolfed.com/blog/38) +- [第十六篇 : 微服务容错限流Hystrix入门](http://blog.itwolfed.com/blog/39) +- [第十七篇 : 微服务容错限流Hystrix之Dashboard](http://blog.itwolfed.com/blog/40) +- [第十八篇 : 微服务容错限流Hystrix之流聚合](http://blog.itwolfed.com/blog/41) + +### Spring Cloud Gateway 系列 +- [Spring Cloud Gateway 入门](http://blog.itwolfed.com/blog/32) +- [Spring Cloud Gateway 之 Predict](http://blog.itwolfed.com/blog/33) +- [Spring Cloud Gateway 之 Filter](http://blog.itwolfed.com/blog/34) +- [Spring Cloud Gateway 之 限流](http://blog.itwolfed.com/blog/35) +- [Spring Cloud Gateway 之 服务注册与发现](http://blog.itwolfed.com/blog/36) + +### Spring Cloud 源码解析 +- [Spring Cloud 源码 : 客户端负载均衡 Ribbon 源码解析](http://blog.itwolfed.com/blog/42) +- [Spring Cloud 源码 : Eureka 源码分析之 Eureka Client](http://blog.itwolfed.com/blog/43) +- [Spring Cloud 源码 : Eureka 源码分析之 Eureka Server](http://blog.itwolfed.com/blog/44) ### Dubbo 系列 -- [Dubbo 教程 | 第一篇 : Dubbo 搭建管理控制台](https://mp.weixin.qq.com/s/UYcmklod_2RLrx-ACHPyVw) -- [Dubbo 教程 | 第二篇 : Dubbo 创建 提供者 消费者](https://mp.weixin.qq.com/s/2CRFwbc45oh5Nqd7eREAAg) -- [Dubbo 教程 | 第三篇 : Dubbo 配置](https://mp.weixin.qq.com/s/Dld2DYSbSXmIQxFVE31RNQ) -- [Dubbo 教程 | 第四篇 : Dubbo 高可用](https://mp.weixin.qq.com/s/f0vsJ8jcF24ji5UNlCq1zQ) +- [Dubbo 教程 | 第一篇 : Dubbo 搭建管理控制台](http://blog.itwolfed.com/blog/82) +- [Dubbo 教程 | 第二篇 : Dubbo 创建 提供者 消费者](http://blog.itwolfed.com/blog/83) +- [Dubbo 教程 | 第三篇 : Dubbo 配置](http://blog.itwolfed.com/blog/84) +- [Dubbo 教程 | 第四篇 : Dubbo 高可用](http://blog.itwolfed.com/blog/85) ### Docker 系列 -- [Docker 教程 | 第一篇 : Docker的基本概念和框架](https://mp.weixin.qq.com/s/8VM-c_UkxYcVw2Itiapw4w) -- [Docker 教程 | 第二篇 : Docker 常用操作命令](https://mp.weixin.qq.com/s/S9VkzSJx_JOY8zDiC_nuEg) -- [Docker 教程 | 第三篇 : Docker 获取和推送镜像](https://mp.weixin.qq.com/s/jN-8YgxDcAvwoiZ_BJQUKQ) -- [Docker 教程 | 第四篇 : Docker 构建镜像](https://mp.weixin.qq.com/s/foVeANf0imgU4hfOempp3A) -- [Docker 教程 | 第五篇 : Docker 容器的网络连接](https://mp.weixin.qq.com/s/DzF-ZwaY4QtlgM32I5wybg) -- [Docker 教程 | 第六篇 : Docker 容器的数据管理](https://mp.weixin.qq.com/s/qg8eXHobNxzfPAaHB3U9cw) -- [Docker 教程 | 第七篇 : Docker 私有仓库搭建](https://mp.weixin.qq.com/s/tBh6kT4I5XniCoFEcn7W9A) -- [Docker 教程 | 第八篇 : 服务 Docker 化](https://mp.weixin.qq.com/s/E_gJFbRaWOE-mnVR1lsYfQ) -- [Docker 教程 | 第九篇 : Docker Swarm 集群环境搭建](https://mp.weixin.qq.com/s/RSNL-V4jLE8YVMSWZlJ_Vw) -- [Docker 教程 | 第十篇 : Docker Swarm 微服务部署](https://mp.weixin.qq.com/s/nWpbqAheuTh45dWsgszieA) +- [Docker 教程 | 第一篇 : Docker的基本概念和框架](http://blog.itwolfed.com/blog/86) +- [Docker 教程 | 第二篇 : Docker 常用操作命令](http://blog.itwolfed.com/blog/87) +- [Docker 教程 | 第三篇 : Docker 获取和推送镜像](http://blog.itwolfed.com/blog/88) +- [Docker 教程 | 第四篇 : Docker 构建镜像](http://blog.itwolfed.com/blog/89) +- [Docker 教程 | 第五篇 : Docker 容器的网络连接](http://blog.itwolfed.com/blog/90) +- [Docker 教程 | 第六篇 : Docker 容器的数据管理](http://blog.itwolfed.com/blog/91) +- [Docker 教程 | 第七篇 : Docker 私有仓库搭建](http://blog.itwolfed.com/blog/92) +- [Docker 教程 | 第八篇 : 服务 Docker 化](http://blog.itwolfed.com/blog/93) +- [Docker 教程 | 第九篇 : Docker Swarm 集群环境搭建](http://blog.itwolfed.com/blog/94) +- [Docker 教程 | 第十篇 : Docker Swarm 微服务部署](http://blog.itwolfed.com/blog/95) ### 关注我

- +
欢迎扫码或微信搜索公众号《程序员果果》关注我,更多精彩内容不能错过 ~~

- (转载本站文章请注明作者和出处 程序员果果的博客 + (转载本站文章请注明作者和出处 程序员果果的博客

diff --git a/springboot-actuator-prometheus/pom.xml b/springboot-actuator-prometheus/pom.xml new file mode 100755 index 0000000..7e7e42e --- /dev/null +++ b/springboot-actuator-prometheus/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.9.RELEASE + + + com.gf + springboot-actuator-prometheus + 0.0.1-SNAPSHOT + springboot-actuator-prometheus + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-web + + + io.micrometer + micrometer-registry-prometheus + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot-actuator-prometheus/src/main/java/com/gf/SpringbootActuatorPrometheusDemoApplication.java b/springboot-actuator-prometheus/src/main/java/com/gf/SpringbootActuatorPrometheusDemoApplication.java new file mode 100755 index 0000000..7eed731 --- /dev/null +++ b/springboot-actuator-prometheus/src/main/java/com/gf/SpringbootActuatorPrometheusDemoApplication.java @@ -0,0 +1,42 @@ +package com.gf; + +import io.micrometer.core.instrument.MeterRegistry; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@SpringBootApplication +@RestController +public class SpringbootActuatorPrometheusDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringbootActuatorPrometheusDemoApplication.class, args); + } + + @RequestMapping(value = "/hello") + public String sayHello() { + for (int i = 1 ; i <= 10 ; i++) { + Thread t = new Thread(() -> { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } , "HelloThread - " + i); + t.start(); + } + return "ok"; + } + + /** + @Bean + MeterRegistryCustomizer metricsCommonTags() { + return registry -> registry.config().commonTags("application", "springboot-actuator-prometheus-demo"); + } + */ + +} diff --git a/springboot-actuator-prometheus/src/main/resources/application.yml b/springboot-actuator-prometheus/src/main/resources/application.yml new file mode 100755 index 0000000..9e23bc6 --- /dev/null +++ b/springboot-actuator-prometheus/src/main/resources/application.yml @@ -0,0 +1,14 @@ +management: + endpoints: + web: + exposure: + include: '*' + + endpoint: + health: + show-details: always + + metrics: + tags: + application: actuator-demo + diff --git a/springboot-actuator-prometheus/src/test/java/com/gf/SpringbootActuatorPrometheusDemoApplicationTests.java b/springboot-actuator-prometheus/src/test/java/com/gf/SpringbootActuatorPrometheusDemoApplicationTests.java new file mode 100755 index 0000000..8b7c640 --- /dev/null +++ b/springboot-actuator-prometheus/src/test/java/com/gf/SpringbootActuatorPrometheusDemoApplicationTests.java @@ -0,0 +1,16 @@ +package com.gf; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SpringbootActuatorPrometheusDemoApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/springboot-jsr303/.gitignore b/springboot-jsr303/.gitignore new file mode 100644 index 0000000..a2a3040 --- /dev/null +++ b/springboot-jsr303/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/springboot-jsr303/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-jsr303/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..24c6680 --- /dev/null +++ b/springboot-jsr303/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007-present 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. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println( "- Downloader started" ); + File baseDirectory = new File( args[0] ); + System.out.println( "- Using base directory: " + baseDirectory.getAbsolutePath() ); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File( baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH ); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream( mavenWrapperPropertyFile ); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load( mavenWrapperPropertyFileInputStream ); + url = mavenWrapperProperties.getProperty( PROPERTY_NAME_WRAPPER_URL, url ); + } catch (IOException e) { + System.out.println( "- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'" ); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println( "- Downloading from: " + url ); + + File outputFile = new File( baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH ); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'" ); + } + } + System.out.println( "- Downloading to: " + outputFile.getAbsolutePath() ); + try { + downloadFileFromURL( url, outputFile ); + System.out.println( "Done" ); + System.exit( 0 ); + } catch (Throwable e) { + System.out.println( "- Error downloading" ); + e.printStackTrace(); + System.exit( 1 ); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null) { + String username = System.getenv( "MVNW_USERNAME" ); + char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray(); + Authenticator.setDefault( new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication( username, password ); + } + } ); + } + URL website = new URL( urlString ); + ReadableByteChannel rbc; + rbc = Channels.newChannel( website.openStream() ); + FileOutputStream fos = new FileOutputStream( destination ); + fos.getChannel().transferFrom( rbc, 0, Long.MAX_VALUE ); + fos.close(); + rbc.close(); + } + +} diff --git a/springboot-jsr303/.mvn/wrapper/maven-wrapper.jar b/springboot-jsr303/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..2cc7d4a Binary files /dev/null and b/springboot-jsr303/.mvn/wrapper/maven-wrapper.jar differ diff --git a/springboot-jsr303/.mvn/wrapper/maven-wrapper.properties b/springboot-jsr303/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..642d572 --- /dev/null +++ b/springboot-jsr303/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/springboot-jsr303/pom.xml b/springboot-jsr303/pom.xml new file mode 100644 index 0000000..e42f567 --- /dev/null +++ b/springboot-jsr303/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.0.RELEASE + + + com.itwolfed + springboot-jsr303 + 0.0.1-SNAPSHOT + springboot-jsr303 + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot-jsr303/src/main/java/com/itwolfed/SpringbootJsr303Application.java b/springboot-jsr303/src/main/java/com/itwolfed/SpringbootJsr303Application.java new file mode 100644 index 0000000..c45a832 --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/SpringbootJsr303Application.java @@ -0,0 +1,13 @@ +package com.itwolfed; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringbootJsr303Application { + + public static void main(String[] args) { + SpringApplication.run( SpringbootJsr303Application.class, args ); + } + +} diff --git a/springboot-jsr303/src/main/java/com/itwolfed/controller/UserController.java b/springboot-jsr303/src/main/java/com/itwolfed/controller/UserController.java new file mode 100644 index 0000000..a3832ab --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/controller/UserController.java @@ -0,0 +1,21 @@ +package com.itwolfed.controller; + +import com.itwolfed.entity.User; +import com.itwolfed.utils.Result; +import com.itwolfed.valid.Groups; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/user") +public class UserController { + + @PostMapping("") + public Result save (@Validated(Groups.Add.class) User user) { + return Result.ok(); + } + +} diff --git a/springboot-jsr303/src/main/java/com/itwolfed/entity/User.java b/springboot-jsr303/src/main/java/com/itwolfed/entity/User.java new file mode 100644 index 0000000..3de6ffe --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/entity/User.java @@ -0,0 +1,30 @@ +package com.itwolfed.entity; + +import com.itwolfed.valid.Groups; +import com.itwolfed.valid.ListValue; +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Null; +import javax.validation.constraints.Pattern; + + +@Data +public class User { + + @Null(message = "新增不需要指定id" , groups = Groups.Add.class) + @NotNull(message = "修改需要指定id" , groups = Groups.Update.class) + private Integer id; + @NotBlank(message = "用户名不能为空") + @NotNull + private String username; + @Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合") + private String password; + @Email + private String email; + @ListValue( message = "性别应指定相应的值" , vals = {1,2} , groups = {Groups.Add.class , Groups.Update.class}) + private Integer gender; + +} diff --git a/springboot-jsr303/src/main/java/com/itwolfed/exception/GlobalExceptionControllerAdvice.java b/springboot-jsr303/src/main/java/com/itwolfed/exception/GlobalExceptionControllerAdvice.java new file mode 100644 index 0000000..03abdd3 --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/exception/GlobalExceptionControllerAdvice.java @@ -0,0 +1,36 @@ +package com.itwolfed.exception; + +import com.itwolfed.utils.Result; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; + +/** + * 统一异常处理 + */ +@Slf4j +@RestControllerAdvice(basePackages = "com.itwolfed.controller") +public class GlobalExceptionControllerAdvice { + + @ExceptionHandler(value= {MethodArgumentNotValidException.class , BindException.class}) + public Result handleVaildException(Exception e){ + BindingResult bindingResult = null; + if (e instanceof MethodArgumentNotValidException) { + bindingResult = ((MethodArgumentNotValidException)e).getBindingResult(); + } else if (e instanceof BindException) { + bindingResult = ((BindException)e).getBindingResult(); + } + Map errorMap = new HashMap<>(16); + bindingResult.getFieldErrors().forEach((fieldError)-> + errorMap.put(fieldError.getField(),fieldError.getDefaultMessage()) + ); + return Result.build(400 , "非法参数 !" , errorMap); + } + +} diff --git a/springboot-jsr303/src/main/java/com/itwolfed/utils/Result.java b/springboot-jsr303/src/main/java/com/itwolfed/utils/Result.java new file mode 100644 index 0000000..fb0600f --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/utils/Result.java @@ -0,0 +1,63 @@ +package com.itwolfed.utils; + + +import lombok.Getter; +import lombok.Setter; + +/** + * 自定义响应结构 + */ +@Getter +@Setter +public class Result { + + // 响应业务状态 + private Integer status; + + // 响应消息 + private String msg; + + // 响应中的数据 + private Object data; + + + public Result() { + + } + + public static Result ok(Object data) { + + return new Result(200 , data); + } + + public static Result ok() { + return new Result(200 , null); + } + + public static Result build(Integer status, String msg) { + return new Result(status, msg, null); + } + + + public static Result build(Integer status, String msg , Object data) { + return new Result(status,msg,data); + } + + public Result(Integer status,String msg) { + this.status = status; + this.msg = msg; + } + + + public Result(Integer status,Object data) { + this.status = status; + this.data = data; + } + + public Result(Integer status, String msg, Object data) { + this.status = status; + this.msg = msg; + this.data = data; + } + +} \ No newline at end of file diff --git a/springboot-jsr303/src/main/java/com/itwolfed/valid/Groups.java b/springboot-jsr303/src/main/java/com/itwolfed/valid/Groups.java new file mode 100644 index 0000000..621049d --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/valid/Groups.java @@ -0,0 +1,7 @@ +package com.itwolfed.valid; + + +public class Groups { + public interface Add{} + public interface Update{} +} diff --git a/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValue.java b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValue.java new file mode 100644 index 0000000..f3effce --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValue.java @@ -0,0 +1,25 @@ +package com.itwolfed.valid; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + + +@Documented +@Constraint(validatedBy = { ListValueConstraintValidator.class }) +@Target({ METHOD, FIELD, ANNOTATION_TYPE }) +@Retention(RUNTIME) +public @interface ListValue { + String message() default ""; + + Class[] groups() default { }; + + Class[] payload() default { }; + + int[] vals() ; +} \ No newline at end of file diff --git a/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValueConstraintValidator.java b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValueConstraintValidator.java new file mode 100644 index 0000000..1b99a94 --- /dev/null +++ b/springboot-jsr303/src/main/java/com/itwolfed/valid/ListValueConstraintValidator.java @@ -0,0 +1,37 @@ +package com.itwolfed.valid; + + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.HashSet; +import java.util.Set; + +public class ListValueConstraintValidator implements ConstraintValidator { + + private Set set = new HashSet<>(); + /** + * 初始化方法 + */ + @Override + public void initialize(ListValue constraintAnnotation) { + + int[] vals = constraintAnnotation.vals(); + for (int val : vals) { + set.add(val); + } + + } + + /** + * 判断是否校验成功 + * + * @param value 需要校验的值 + * @param context + * @return + */ + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + + return set.contains(value); + } +} diff --git a/springboot-jsr303/src/main/resources/application.yml b/springboot-jsr303/src/main/resources/application.yml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/springboot-jsr303/src/main/resources/application.yml @@ -0,0 +1 @@ + diff --git a/springboot-jsr303/src/test/java/com/itwolfed/SpringbootJsr303ApplicationTests.java b/springboot-jsr303/src/test/java/com/itwolfed/SpringbootJsr303ApplicationTests.java new file mode 100644 index 0000000..c6cfbc9 --- /dev/null +++ b/springboot-jsr303/src/test/java/com/itwolfed/SpringbootJsr303ApplicationTests.java @@ -0,0 +1,13 @@ +package com.itwolfed; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringbootJsr303ApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/springboot-rocketmq-message/.gitignore b/springboot-rocketmq-message/.gitignore new file mode 100644 index 0000000..1e4385b --- /dev/null +++ b/springboot-rocketmq-message/.gitignore @@ -0,0 +1,36 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +mvnw.cmd +mvnw +.mvn + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/springboot-rocketmq-message/pom.xml b/springboot-rocketmq-message/pom.xml new file mode 100644 index 0000000..310f5b8 --- /dev/null +++ b/springboot-rocketmq-message/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.10.RELEASE + + + com.itwolfed + springboot-rocketmq-message + 0.0.1-SNAPSHOT + springboot-rocketmq-message + Demo project for Spring Boot + + 1.8 + + + + org.springframework.boot + spring-boot-starter-web + + + org.apache.rocketmq + rocketmq-spring-boot-starter + 2.1.1 + + + org.projectlombok + lombok + 1.18.16 + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/RocketmqMessageNormalApplication.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/RocketmqMessageNormalApplication.java new file mode 100644 index 0000000..43e68eb --- /dev/null +++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/RocketmqMessageNormalApplication.java @@ -0,0 +1,13 @@ +package com.itwolfed; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RocketmqMessageNormalApplication { + + public static void main(String[] args) { + SpringApplication.run( RocketmqMessageNormalApplication.class, args ); + } + +} diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Consumer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Consumer.java new file mode 100644 index 0000000..090ac08 --- /dev/null +++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Consumer.java @@ -0,0 +1,18 @@ +package com.itwolfed.msg; + +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RocketMQMessageListener(topic = "Topic-Normal",consumerGroup = "consumer-msg-group") +public class Consumer implements RocketMQListener { + + @Override + public void onMessage(String message) { + log.info("Receive message:{}" , message); + } + +} diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/DelayConsumer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/DelayConsumer.java new file mode 100644 index 0000000..f85a4c7 --- /dev/null +++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/DelayConsumer.java @@ -0,0 +1,18 @@ +package com.itwolfed.msg; + +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RocketMQMessageListener(topic = "Topic-Delay",consumerGroup = "consumer-delay-group") +public class DelayConsumer implements RocketMQListener { + + @Override + public void onMessage(String message) { + log.info("Receive message:{}" , message); + } + +} diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/OrderConsumer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/OrderConsumer.java new file mode 100644 index 0000000..994aa25 --- /dev/null +++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/OrderConsumer.java @@ -0,0 +1,18 @@ +package com.itwolfed.msg; + +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RocketMQMessageListener(topic = "Topic-Order",consumerGroup = "consumer-order-group") +public class OrderConsumer implements RocketMQListener { + + @Override + public void onMessage(String message) { + log.info("Receive message:{}" , message); + } + +} diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Producer.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Producer.java new file mode 100644 index 0000000..71b9709 --- /dev/null +++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/Producer.java @@ -0,0 +1,128 @@ +package com.itwolfed.msg; + +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.client.producer.LocalTransactionState; +import org.apache.rocketmq.client.producer.SendCallback; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.client.producer.TransactionSendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +public class Producer { + + + @Autowired + private RocketMQTemplate rocketMQTemplate; + + /** + * 普通消息 + */ + public void sendMsg() throws Exception { + + Message message = new Message( + // 普通消息所属的Topic + "Topic-Normal", + // Message Tag可理解为Gmail中的标签,对消息进行再归类,方便Consumer指定过滤条件在消息队列 RocketMQ 版的服务器过滤。 + "TagA", + // Message Body可以是任何二进制形式的数据。 + "Hello MQ".getBytes() + ); + rocketMQTemplate.getProducer().send( message ); + // 等同于上面的方式(常用) + //rocketMQTemplate.convertAndSend("Topic-Normal:TagA","Hello MQ".getBytes()); + } + + /** + * 异步发送普通消息 + */ + public void sendAsyncMsg() { + Map map = new HashMap<>(); + map.put( "name", "zs" ); + map.put( "age", 20 ); + + rocketMQTemplate.asyncSend( "Topic-Normal", map, new SendCallback() { + @Override + public void onSuccess(SendResult sendResult) { + // 消息发送成功。 + log.info( "async send success" ); + } + + @Override + public void onException(Throwable throwable) { + // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理。 + log.info( "async send fail" ); + } + } ); + } + + /** + * 顺序消息 + */ + public void sendOrderlyMsg() { + //根据指定的hashKey按顺序发送 + for (int i = 0; i < 1000; i++) { + String orderId = "biz_" + i % 10; + // 分区顺序消息中区分不同分区的关键字段,Sharding Key与普通消息的key是完全不同的概念。 + // 全局顺序消息,该字段可以设置为任意非空字符串。 + String shardingKey = String.valueOf( orderId ); + try { + SendResult sendResult = rocketMQTemplate.syncSendOrderly( "Topic-Order", "send order msg".getBytes(), shardingKey ); + // 发送消息,只要不抛异常就是成功。 + if (sendResult != null) { + System.out.println( new Date() + " Send mq message success . msgId is:" + sendResult.getMsgId() ); + } + } catch (Exception e) { + // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理。 + System.out.println( new Date() + " Send mq message failed" ); + e.printStackTrace(); + } + } + } + + /** + * 延时消息 + */ + public void sendDelayMsg() { + rocketMQTemplate.syncSend( "Topic-Delay", + MessageBuilder.withPayload( "Hello MQ".getBytes() ).build(), + 3000, + //设置延时等级3,这个消息将在10s之后发送(现在只支持固定的几个时间,详看delayTimeLevel) + //messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; + 3 ); + } + + /** + * 批量消息 + */ + public void sendBatchMsg(List messages) { + rocketMQTemplate.syncSend( "springboot-rocketmq", messages ); + + } + + /** + * 事务消息 + */ + public void sendTransactionMsg(){ + TransactionSendResult transactionSendResult = rocketMQTemplate.sendMessageInTransaction( + "Topic-Tx:TagA", + MessageBuilder.withPayload( "Hello MQ transaction===".getBytes() ).build(), + null ); + SendStatus sendStatus = transactionSendResult.getSendStatus(); + LocalTransactionState localTransactionState = transactionSendResult.getLocalTransactionState(); + + System.out.println( new Date() + " Send mq message status "+ sendStatus +" , localTransactionState "+ localTransactionState ); + } + + +} diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxConsumerListener.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxConsumerListener.java new file mode 100644 index 0000000..84975de --- /dev/null +++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxConsumerListener.java @@ -0,0 +1,22 @@ +package com.itwolfed.msg; + +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + + +@Component +@Slf4j +@RocketMQMessageListener(topic = "Topic-Tx",consumerGroup = "consumer-tx-group") +public class TxConsumerListener implements RocketMQListener { + + + + @Override + public void onMessage(String message) { + + log.info("Receive message:{}" , message); + } + +} diff --git a/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxProducerListener.java b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxProducerListener.java new file mode 100644 index 0000000..3eb5c8a --- /dev/null +++ b/springboot-rocketmq-message/src/main/java/com/itwolfed/msg/TxProducerListener.java @@ -0,0 +1,45 @@ +package com.itwolfed.msg; + +import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener; +import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener; +import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Component; + + +@Component +@RocketMQTransactionListener +public class TxProducerListener implements RocketMQLocalTransactionListener { + + @Override + public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) { + // 执行本地事务 + System.out.println("TX message listener execute local transaction"); + RocketMQLocalTransactionState result; + try { + // 业务代码( 例如下订单 ) + result = RocketMQLocalTransactionState.COMMIT; + } catch (Exception e) { + System.out.println("execute local transaction error"); + result = RocketMQLocalTransactionState.UNKNOWN; + } + return result; + } + + @Override + public RocketMQLocalTransactionState checkLocalTransaction(Message msg) { + // 检查本地事务( 例如检查下订单是否成功 ) + System.out.println("TX message listener check local transaction"); + RocketMQLocalTransactionState result; + try { + //业务代码( 根据检查结果,决定是COMMIT或ROLLBACK ) + result = RocketMQLocalTransactionState.COMMIT; + } catch (Exception e) { + // 异常就回滚 + System.out.println("check local transaction error"); + result = RocketMQLocalTransactionState.ROLLBACK; + } + return result; + } + +} diff --git a/springboot-rocketmq-message/src/main/resources/application.yml b/springboot-rocketmq-message/src/main/resources/application.yml new file mode 100644 index 0000000..fa3511d --- /dev/null +++ b/springboot-rocketmq-message/src/main/resources/application.yml @@ -0,0 +1,7 @@ +server: + port: 8080 + +rocketmq: + name-server: 172.16.250.129:9876 + producer: + group: myGroup \ No newline at end of file diff --git a/springboot-rocketmq-message/src/test/java/com/itwolfed/RocketmqMessageNormalApplicationTests.java b/springboot-rocketmq-message/src/test/java/com/itwolfed/RocketmqMessageNormalApplicationTests.java new file mode 100644 index 0000000..29f75c4 --- /dev/null +++ b/springboot-rocketmq-message/src/test/java/com/itwolfed/RocketmqMessageNormalApplicationTests.java @@ -0,0 +1,62 @@ +package com.itwolfed; + + +import com.itwolfed.msg.Producer; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + + +@RunWith(SpringRunner.class) +@SpringBootTest +public class RocketmqMessageNormalApplicationTests { + + @Autowired + private Producer producer; + + + + /** + * 测试普通消息 + */ + @Test + public void sendMsg() throws Exception { + producer.sendMsg(); + } + + /** + * 异步发送普通消息 + */ + @Test + public void sendAsyncMsg() { + producer.sendAsyncMsg(); + } + + /** + * 顺序消息 + */ + @Test + public void sendOrderlyMsg() { + producer.sendOrderlyMsg(); + } + + /** + * 延时消息 + */ + @Test + public void sendDelayMsg() { + producer.sendDelayMsg(); + } + + /** + * 事务消息 + */ + @Test + public void sendTransactionMsg(){ + producer.sendTransactionMsg(); + } + + +} diff --git a/springboot-seata/sbm-account-service/.gitignore b/springboot-seata/sbm-account-service/.gitignore new file mode 100755 index 0000000..a2a3040 --- /dev/null +++ b/springboot-seata/sbm-account-service/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/springboot-seata/sbm-account-service/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-seata/sbm-account-service/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100755 index 0000000..7f91a56 --- /dev/null +++ b/springboot-seata/sbm-account-service/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,114 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. +*/ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/springboot-seata/sbm-account-service/.mvn/wrapper/maven-wrapper.jar b/springboot-seata/sbm-account-service/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 0000000..01e6799 Binary files /dev/null and b/springboot-seata/sbm-account-service/.mvn/wrapper/maven-wrapper.jar differ diff --git a/springboot-seata/sbm-account-service/.mvn/wrapper/maven-wrapper.properties b/springboot-seata/sbm-account-service/.mvn/wrapper/maven-wrapper.properties new file mode 100755 index 0000000..cd0d451 --- /dev/null +++ b/springboot-seata/sbm-account-service/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-seata/sbm-account-service/pom.xml b/springboot-seata/sbm-account-service/pom.xml new file mode 100755 index 0000000..af89d5d --- /dev/null +++ b/springboot-seata/sbm-account-service/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.10.RELEASE + + + com.gf + sbm-account-service + 0.0.1-SNAPSHOT + sbm-account-service + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + io.seata + seata-spring-boot-starter + 1.0.0 + + + org.projectlombok + lombok + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.0 + + + mysql + mysql-connector-java + runtime + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/SbmAccountServiceApplication.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/SbmAccountServiceApplication.java new file mode 100755 index 0000000..a209f9f --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/SbmAccountServiceApplication.java @@ -0,0 +1,22 @@ +package com.gf; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication(scanBasePackages = "com.gf", exclude = DataSourceAutoConfiguration.class) +public class SbmAccountServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(SbmAccountServiceApplication.class, args); + } + + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + return restTemplate; + } + +} diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/config/DataSourceConfig.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/config/DataSourceConfig.java new file mode 100755 index 0000000..0d0a6a8 --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/config/DataSourceConfig.java @@ -0,0 +1,21 @@ +package com.gf.config; + +import com.alibaba.druid.pool.DruidDataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceConfig { + + @Bean + @ConfigurationProperties(prefix = "spring.datasource") + public DataSource druidDataSource() { + DruidDataSource druidDataSource = new DruidDataSource(); + return druidDataSource; + } + + +} \ No newline at end of file diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java new file mode 100755 index 0000000..b8c3778 --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java @@ -0,0 +1,47 @@ +package com.gf.config; + +import com.gf.interceptor.SeataRestTemplateInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +@Configuration +public class SeataRestTemplateAutoConfiguration { + @Autowired( + required = false + ) + private Collection restTemplates; + @Autowired + private SeataRestTemplateInterceptor seataRestTemplateInterceptor; + + public SeataRestTemplateAutoConfiguration() { + } + + @Bean + public SeataRestTemplateInterceptor seataRestTemplateInterceptor() { + return new SeataRestTemplateInterceptor(); + } + + @PostConstruct + public void init() { + if (this.restTemplates != null) { + Iterator var1 = this.restTemplates.iterator(); + + while (var1.hasNext()) { + RestTemplate restTemplate = (RestTemplate) var1.next(); + List interceptors = new ArrayList(restTemplate.getInterceptors()); + interceptors.add(this.seataRestTemplateInterceptor); + restTemplate.setInterceptors(interceptors); + } + } + + } +} diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/controller/AccountController.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/controller/AccountController.java new file mode 100755 index 0000000..c2a588f --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/controller/AccountController.java @@ -0,0 +1,25 @@ +package com.gf.controller; + +import com.gf.service.AccountService; +import io.seata.core.context.RootContext; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.math.BigDecimal; + +@RestController +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class AccountController { + + private final AccountService accountService; + + @GetMapping + public void debit(@RequestParam String userId , @RequestParam BigDecimal orderMoney) { + System.out.println("account XID " + RootContext.getXID()); + accountService.debit(userId , orderMoney); + } + +} diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/entity/Account.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/entity/Account.java new file mode 100755 index 0000000..7cf8431 --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/entity/Account.java @@ -0,0 +1,16 @@ +package com.gf.entity; + +import lombok.*; + +import java.math.BigDecimal; + +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class Account { + private Integer id; + private String userId; + private BigDecimal money; +} diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/filter/SeataFilter.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/filter/SeataFilter.java new file mode 100755 index 0000000..cf6e77f --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/filter/SeataFilter.java @@ -0,0 +1,43 @@ +package com.gf.filter; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Component; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@Component +public class SeataFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) servletRequest; + String xid = req.getHeader(RootContext.KEY_XID.toLowerCase()); + boolean isBind = false; + if (StringUtils.isNotBlank(xid)) { + RootContext.bind(xid); + isBind = true; + } + try { + filterChain.doFilter(servletRequest, servletResponse); + } finally { + if (isBind) { + RootContext.unbind(); + } + } + } + + @Override + public void destroy() { + } +} diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java new file mode 100755 index 0000000..ac547a0 --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java @@ -0,0 +1,27 @@ +package com.gf.interceptor; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; + +import java.io.IOException; + +public class SeataRestTemplateInterceptor implements ClientHttpRequestInterceptor { + public SeataRestTemplateInterceptor() { + } + + @Override + public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest); + String xid = RootContext.getXID(); + if (StringUtils.isNotEmpty(xid)) { + requestWrapper.getHeaders().add(RootContext.KEY_XID, xid); + } + + return clientHttpRequestExecution.execute(requestWrapper, bytes); + } +} diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/mapper/AccountMapper.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/mapper/AccountMapper.java new file mode 100755 index 0000000..7210930 --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/mapper/AccountMapper.java @@ -0,0 +1,15 @@ +package com.gf.mapper; + + +import com.gf.entity.Account; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface AccountMapper { + + Account selectByUserId(@Param("userId") String userId); + + int updateById(@Param("account") Account record); + +} diff --git a/springboot-seata/sbm-account-service/src/main/java/com/gf/service/AccountService.java b/springboot-seata/sbm-account-service/src/main/java/com/gf/service/AccountService.java new file mode 100755 index 0000000..e7d8b7e --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/java/com/gf/service/AccountService.java @@ -0,0 +1,29 @@ +package com.gf.service; + +import com.gf.entity.Account; +import com.gf.mapper.AccountMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +@Service +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class AccountService { + + private static final String ERROR_USER_ID = "1002"; + + private final AccountMapper accountMapper; + + public void debit(String userId , BigDecimal num) { + Account account = accountMapper.selectByUserId(userId); + account.setMoney(account.getMoney().subtract(num)); + accountMapper.updateById(account); + + if (ERROR_USER_ID.equals(userId)) { + throw new RuntimeException("account branch exception"); + } + } + +} diff --git a/springboot-seata/sbm-account-service/src/main/resources/application.properties b/springboot-seata/sbm-account-service/src/main/resources/application.properties new file mode 100755 index 0000000..231768c --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/resources/application.properties @@ -0,0 +1,10 @@ +spring.application.name=account-service +server.port=8081 +spring.datasource.url=jdbc:mysql://172.16.2.101:3306/db_seata?useSSL=false&serverTimezone=UTC +spring.datasource.username=root +spring.datasource.password=123456 +seata.tx-service-group=my_test_tx_group +mybatis.mapper-locations=classpath*:mapper/*Mapper.xml +seata.service.grouplist=172.16.2.101:8091 +logging.level.io.seata=info +logging.level.io.seata.samples.account.persistence.AccountMapper=debug diff --git a/springboot-seata/sbm-account-service/src/main/resources/mapper/AccountMapper.xml b/springboot-seata/sbm-account-service/src/main/resources/mapper/AccountMapper.xml new file mode 100755 index 0000000..e2af415 --- /dev/null +++ b/springboot-seata/sbm-account-service/src/main/resources/mapper/AccountMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + update account_tbl + set money = #{account.money,jdbcType=DECIMAL} + where id = #{account.id} + + + \ No newline at end of file diff --git a/springboot-seata/sbm-account-service/src/test/java/com/gf/SbmAccountServiceApplicationTests.java b/springboot-seata/sbm-account-service/src/test/java/com/gf/SbmAccountServiceApplicationTests.java new file mode 100755 index 0000000..e69de29 diff --git a/springboot-seata/sbm-business-service/.gitignore b/springboot-seata/sbm-business-service/.gitignore new file mode 100755 index 0000000..a2a3040 --- /dev/null +++ b/springboot-seata/sbm-business-service/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/springboot-seata/sbm-business-service/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-seata/sbm-business-service/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100755 index 0000000..7f91a56 --- /dev/null +++ b/springboot-seata/sbm-business-service/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,114 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. +*/ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/springboot-seata/sbm-business-service/.mvn/wrapper/maven-wrapper.jar b/springboot-seata/sbm-business-service/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 0000000..01e6799 Binary files /dev/null and b/springboot-seata/sbm-business-service/.mvn/wrapper/maven-wrapper.jar differ diff --git a/springboot-seata/sbm-business-service/.mvn/wrapper/maven-wrapper.properties b/springboot-seata/sbm-business-service/.mvn/wrapper/maven-wrapper.properties new file mode 100755 index 0000000..cd0d451 --- /dev/null +++ b/springboot-seata/sbm-business-service/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-seata/sbm-business-service/pom.xml b/springboot-seata/sbm-business-service/pom.xml new file mode 100755 index 0000000..dba052e --- /dev/null +++ b/springboot-seata/sbm-business-service/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.10.RELEASE + + + com.gf + sbm-business-service + 0.0.1-SNAPSHOT + sbm-business-service + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + + + io.seata + seata-spring-boot-starter + 1.0.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/SbmBusinessServiceApplication.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/SbmBusinessServiceApplication.java new file mode 100755 index 0000000..e5975bf --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/SbmBusinessServiceApplication.java @@ -0,0 +1,23 @@ +package com.gf; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication(scanBasePackages = "com.gf", exclude = DataSourceAutoConfiguration.class) +public class SbmBusinessServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(SbmBusinessServiceApplication.class, args); + } + + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + return restTemplate; + } + + +} diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/client/OrderClient.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/client/OrderClient.java new file mode 100755 index 0000000..bc1ba65 --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/client/OrderClient.java @@ -0,0 +1,25 @@ +package com.gf.client; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class OrderClient { + + private final RestTemplate restTemplate; + + public void create(String userId, String commodityCode, int orderCount) { + String url = "http://127.0.0.1:8082/api/order/debit?userId=" + userId + "&commodityCode=" + commodityCode + "&count=" + orderCount; + try { + restTemplate.getForEntity(url, Void.class); + } catch (Exception e) { + log.error("create url {} ,error:", url); + throw new RuntimeException(); + } + } +} diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/client/StorageClient.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/client/StorageClient.java new file mode 100755 index 0000000..7fc9eed --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/client/StorageClient.java @@ -0,0 +1,27 @@ +package com.gf.client; + +import io.seata.core.context.RootContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class StorageClient { + + private final RestTemplate restTemplate; + + public void deduct(String commodityCode, int orderCount) { + System.out.println("business to storage " + RootContext.getXID()); + String url = "http://127.0.0.1:8083/api/storage/deduct?commodityCode=" + commodityCode + "&count=" + orderCount; + try { + restTemplate.getForEntity(url, Void.class); + } catch (Exception e) { + log.error("deduct url {} ,error:", url, e); + throw new RuntimeException(); + } + } +} diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java new file mode 100755 index 0000000..b8c3778 --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java @@ -0,0 +1,47 @@ +package com.gf.config; + +import com.gf.interceptor.SeataRestTemplateInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +@Configuration +public class SeataRestTemplateAutoConfiguration { + @Autowired( + required = false + ) + private Collection restTemplates; + @Autowired + private SeataRestTemplateInterceptor seataRestTemplateInterceptor; + + public SeataRestTemplateAutoConfiguration() { + } + + @Bean + public SeataRestTemplateInterceptor seataRestTemplateInterceptor() { + return new SeataRestTemplateInterceptor(); + } + + @PostConstruct + public void init() { + if (this.restTemplates != null) { + Iterator var1 = this.restTemplates.iterator(); + + while (var1.hasNext()) { + RestTemplate restTemplate = (RestTemplate) var1.next(); + List interceptors = new ArrayList(restTemplate.getInterceptors()); + interceptors.add(this.seataRestTemplateInterceptor); + restTemplate.setInterceptors(interceptors); + } + } + + } +} diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/controller/BusinessController.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/controller/BusinessController.java new file mode 100755 index 0000000..adbd415 --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/controller/BusinessController.java @@ -0,0 +1,45 @@ +package com.gf.controller; + +import com.gf.service.BusinessService; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@RequestMapping("/api/business") +@RestController +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class BusinessController { + + private final BusinessService businessService; + + /** + * 购买下单,模拟全局事务提交 + * + * @return + */ + @RequestMapping("/purchase/commit") + public Boolean purchaseCommit(HttpServletRequest request) { + businessService.purchase("1001", "2001", 1); + return true; + } + + /** + * 购买下单,模拟全局事务回滚 + * + * @return + */ + @RequestMapping("/purchase/rollback") + public Boolean purchaseRollback() { + try { + businessService.purchase("1002", "2001", 1); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/filter/SeataFilter.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/filter/SeataFilter.java new file mode 100755 index 0000000..cf6e77f --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/filter/SeataFilter.java @@ -0,0 +1,43 @@ +package com.gf.filter; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Component; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@Component +public class SeataFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) servletRequest; + String xid = req.getHeader(RootContext.KEY_XID.toLowerCase()); + boolean isBind = false; + if (StringUtils.isNotBlank(xid)) { + RootContext.bind(xid); + isBind = true; + } + try { + filterChain.doFilter(servletRequest, servletResponse); + } finally { + if (isBind) { + RootContext.unbind(); + } + } + } + + @Override + public void destroy() { + } +} diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java new file mode 100755 index 0000000..ac547a0 --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java @@ -0,0 +1,27 @@ +package com.gf.interceptor; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; + +import java.io.IOException; + +public class SeataRestTemplateInterceptor implements ClientHttpRequestInterceptor { + public SeataRestTemplateInterceptor() { + } + + @Override + public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest); + String xid = RootContext.getXID(); + if (StringUtils.isNotEmpty(xid)) { + requestWrapper.getHeaders().add(RootContext.KEY_XID, xid); + } + + return clientHttpRequestExecution.execute(requestWrapper, bytes); + } +} diff --git a/springboot-seata/sbm-business-service/src/main/java/com/gf/service/BusinessService.java b/springboot-seata/sbm-business-service/src/main/java/com/gf/service/BusinessService.java new file mode 100755 index 0000000..f2b3c93 --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/java/com/gf/service/BusinessService.java @@ -0,0 +1,36 @@ +package com.gf.service; + +import com.gf.client.OrderClient; +import com.gf.client.StorageClient; +import io.seata.core.context.RootContext; +import io.seata.spring.annotation.GlobalTransactional; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class BusinessService { + + private static final Logger LOGGER = LoggerFactory.getLogger(BusinessService.class); + + private final StorageClient storageClient; + + private final OrderClient orderClient; + + /** + * 减库存,下订单 + * + * @param userId + * @param commodityCode + * @param orderCount + */ + @GlobalTransactional + public void purchase(String userId, String commodityCode, int orderCount) { + LOGGER.info("purchase begin ... xid: " + RootContext.getXID()); + storageClient.deduct(commodityCode, orderCount); + orderClient.create(userId, commodityCode, orderCount); + } +} diff --git a/springboot-seata/sbm-business-service/src/main/resources/application.properties b/springboot-seata/sbm-business-service/src/main/resources/application.properties new file mode 100755 index 0000000..8aad42c --- /dev/null +++ b/springboot-seata/sbm-business-service/src/main/resources/application.properties @@ -0,0 +1,5 @@ +spring.application.name=business-service +server.port=8084 +seata.service.grouplist=172.16.2.101:8091 +seata.tx-service-group=my_test_tx_group +logging.level.io.seata=info \ No newline at end of file diff --git a/springboot-seata/sbm-business-service/src/test/java/com/gf/SbmBusinessServiceApplicationTests.java b/springboot-seata/sbm-business-service/src/test/java/com/gf/SbmBusinessServiceApplicationTests.java new file mode 100755 index 0000000..e69de29 diff --git a/springboot-seata/sbm-order-service/.gitignore b/springboot-seata/sbm-order-service/.gitignore new file mode 100755 index 0000000..a2a3040 --- /dev/null +++ b/springboot-seata/sbm-order-service/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/springboot-seata/sbm-order-service/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-seata/sbm-order-service/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100755 index 0000000..7f91a56 --- /dev/null +++ b/springboot-seata/sbm-order-service/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,114 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. +*/ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/springboot-seata/sbm-order-service/.mvn/wrapper/maven-wrapper.jar b/springboot-seata/sbm-order-service/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 0000000..01e6799 Binary files /dev/null and b/springboot-seata/sbm-order-service/.mvn/wrapper/maven-wrapper.jar differ diff --git a/springboot-seata/sbm-order-service/.mvn/wrapper/maven-wrapper.properties b/springboot-seata/sbm-order-service/.mvn/wrapper/maven-wrapper.properties new file mode 100755 index 0000000..cd0d451 --- /dev/null +++ b/springboot-seata/sbm-order-service/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-seata/sbm-order-service/pom.xml b/springboot-seata/sbm-order-service/pom.xml new file mode 100755 index 0000000..e31e09a --- /dev/null +++ b/springboot-seata/sbm-order-service/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.10.RELEASE + + + com.gf + sbm-order-service + 0.0.1-SNAPSHOT + sbm-order-service + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + io.seata + seata-spring-boot-starter + 1.0.0 + + + org.projectlombok + lombok + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.0 + + + mysql + mysql-connector-java + runtime + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/SbmOrderServiceApplication.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/SbmOrderServiceApplication.java new file mode 100755 index 0000000..a447e98 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/SbmOrderServiceApplication.java @@ -0,0 +1,23 @@ +package com.gf; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + + +@SpringBootApplication(scanBasePackages = "com.gf", exclude = DataSourceAutoConfiguration.class) +public class SbmOrderServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(SbmOrderServiceApplication.class, args); + } + + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + return restTemplate; + } + +} diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/client/AccountClient.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/client/AccountClient.java new file mode 100755 index 0000000..17e8a50 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/client/AccountClient.java @@ -0,0 +1,28 @@ +package com.gf.client; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.math.BigDecimal; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class AccountClient { + + private final RestTemplate restTemplate; + + public void debit(String userId, BigDecimal orderMoney) { + String url = "http://127.0.0.1:8081?userId=" + userId + "&orderMoney=" + orderMoney; + try { + restTemplate.getForEntity(url, Void.class); + } catch (Exception e) { + log.error("debit url {} ,error:", url, e); + throw new RuntimeException(); + } + } + +} diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/config/DataSourceConfig.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/config/DataSourceConfig.java new file mode 100755 index 0000000..82d94b3 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/config/DataSourceConfig.java @@ -0,0 +1,26 @@ +package com.gf.config; + +import com.alibaba.druid.pool.DruidDataSource; +import io.seata.rm.datasource.DataSourceProxy; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceConfig { + + @Bean + @ConfigurationProperties(prefix = "spring.datasource") + public DataSource druidDataSource() { + DruidDataSource druidDataSource = new DruidDataSource(); + return druidDataSource; + } + + +} \ No newline at end of file diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java new file mode 100755 index 0000000..b8c3778 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java @@ -0,0 +1,47 @@ +package com.gf.config; + +import com.gf.interceptor.SeataRestTemplateInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +@Configuration +public class SeataRestTemplateAutoConfiguration { + @Autowired( + required = false + ) + private Collection restTemplates; + @Autowired + private SeataRestTemplateInterceptor seataRestTemplateInterceptor; + + public SeataRestTemplateAutoConfiguration() { + } + + @Bean + public SeataRestTemplateInterceptor seataRestTemplateInterceptor() { + return new SeataRestTemplateInterceptor(); + } + + @PostConstruct + public void init() { + if (this.restTemplates != null) { + Iterator var1 = this.restTemplates.iterator(); + + while (var1.hasNext()) { + RestTemplate restTemplate = (RestTemplate) var1.next(); + List interceptors = new ArrayList(restTemplate.getInterceptors()); + interceptors.add(this.seataRestTemplateInterceptor); + restTemplate.setInterceptors(interceptors); + } + } + + } +} diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/controller/OrderController.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/controller/OrderController.java new file mode 100755 index 0000000..260d634 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/controller/OrderController.java @@ -0,0 +1,25 @@ +package com.gf.controller; + +import com.gf.service.OrderService; +import io.seata.core.context.RootContext; +import lombok.RequiredArgsConstructor; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RequestMapping("/api/order") +@RestController +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class OrderController { + + private final OrderService orderService; + + @GetMapping(value = "/debit") + public void debit(@RequestParam String userId, @RequestParam String commodityCode, @RequestParam Integer count) { + System.out.println("order XID " + RootContext.getXID()); + orderService.create(userId, commodityCode, count); + } + +} diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/entity/Order.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/entity/Order.java new file mode 100755 index 0000000..b221bca --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/entity/Order.java @@ -0,0 +1,23 @@ +package com.gf.entity; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.math.BigDecimal; + +@Getter +@Setter +@ToString +public class Order { + private Integer id; + + private String userId; + + private String commodityCode; + + private Integer count; + + private BigDecimal money; + +} diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/filter/SeataFilter.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/filter/SeataFilter.java new file mode 100755 index 0000000..cf6e77f --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/filter/SeataFilter.java @@ -0,0 +1,43 @@ +package com.gf.filter; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Component; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@Component +public class SeataFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) servletRequest; + String xid = req.getHeader(RootContext.KEY_XID.toLowerCase()); + boolean isBind = false; + if (StringUtils.isNotBlank(xid)) { + RootContext.bind(xid); + isBind = true; + } + try { + filterChain.doFilter(servletRequest, servletResponse); + } finally { + if (isBind) { + RootContext.unbind(); + } + } + } + + @Override + public void destroy() { + } +} diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java new file mode 100755 index 0000000..ac547a0 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java @@ -0,0 +1,27 @@ +package com.gf.interceptor; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; + +import java.io.IOException; + +public class SeataRestTemplateInterceptor implements ClientHttpRequestInterceptor { + public SeataRestTemplateInterceptor() { + } + + @Override + public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest); + String xid = RootContext.getXID(); + if (StringUtils.isNotEmpty(xid)) { + requestWrapper.getHeaders().add(RootContext.KEY_XID, xid); + } + + return clientHttpRequestExecution.execute(requestWrapper, bytes); + } +} diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/mapper/OrderMapper.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/mapper/OrderMapper.java new file mode 100755 index 0000000..ed6f317 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/mapper/OrderMapper.java @@ -0,0 +1,12 @@ +package com.gf.mapper; + +import com.gf.entity.Order; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface OrderMapper { + + int insert(@Param("order") Order record); + +} \ No newline at end of file diff --git a/springboot-seata/sbm-order-service/src/main/java/com/gf/service/OrderService.java b/springboot-seata/sbm-order-service/src/main/java/com/gf/service/OrderService.java new file mode 100755 index 0000000..924ab33 --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/java/com/gf/service/OrderService.java @@ -0,0 +1,32 @@ +package com.gf.service; + +import com.gf.client.AccountClient; +import com.gf.entity.Order; +import com.gf.mapper.OrderMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +@Service +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class OrderService { + + private final AccountClient accountClient; + + private final OrderMapper orderMapper; + + public void create(String userId, String commodityCode, Integer count) { + BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5)); + Order order = new Order(); + order.setUserId(userId); + order.setCommodityCode(commodityCode); + order.setCount(count); + order.setMoney(orderMoney); + + orderMapper.insert(order); + accountClient.debit(userId, orderMoney); + + } +} \ No newline at end of file diff --git a/springboot-seata/sbm-order-service/src/main/resources/application.properties b/springboot-seata/sbm-order-service/src/main/resources/application.properties new file mode 100755 index 0000000..428fe1b --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/resources/application.properties @@ -0,0 +1,10 @@ +spring.application.name=order-service +server.port=8082 +spring.datasource.url=jdbc:mysql://172.16.2.101:3306/db_seata?useSSL=false&serverTimezone=UTC +spring.datasource.username=root +spring.datasource.password=123456 +seata.tx-service-group=my_test_tx_group +mybatis.mapper-locations=classpath*:mapper/*Mapper.xml +seata.service.grouplist=172.16.2.101:8091 +logging.level.io.seata=info +logging.level.io.seata.samples.order.persistence.OrderMapper=debug diff --git a/springboot-seata/sbm-order-service/src/main/resources/mapper/OrderMapper.xml b/springboot-seata/sbm-order-service/src/main/resources/mapper/OrderMapper.xml new file mode 100755 index 0000000..a63398e --- /dev/null +++ b/springboot-seata/sbm-order-service/src/main/resources/mapper/OrderMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + insert into order_tbl (user_id,commodity_code,count,money) + values (#{order.userId}, #{order.commodityCode}, #{order.count}, #{order.money}) + + + \ No newline at end of file diff --git a/springboot-seata/sbm-order-service/src/test/java/com/gf/SbmOrderServiceApplicationTests.java b/springboot-seata/sbm-order-service/src/test/java/com/gf/SbmOrderServiceApplicationTests.java new file mode 100755 index 0000000..e69de29 diff --git a/springboot-seata/sbm-storage-service/.gitignore b/springboot-seata/sbm-storage-service/.gitignore new file mode 100755 index 0000000..a2a3040 --- /dev/null +++ b/springboot-seata/sbm-storage-service/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/springboot-seata/sbm-storage-service/.mvn/wrapper/MavenWrapperDownloader.java b/springboot-seata/sbm-storage-service/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100755 index 0000000..7f91a56 --- /dev/null +++ b/springboot-seata/sbm-storage-service/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,114 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. +*/ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/springboot-seata/sbm-storage-service/.mvn/wrapper/maven-wrapper.jar b/springboot-seata/sbm-storage-service/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 0000000..01e6799 Binary files /dev/null and b/springboot-seata/sbm-storage-service/.mvn/wrapper/maven-wrapper.jar differ diff --git a/springboot-seata/sbm-storage-service/.mvn/wrapper/maven-wrapper.properties b/springboot-seata/sbm-storage-service/.mvn/wrapper/maven-wrapper.properties new file mode 100755 index 0000000..cd0d451 --- /dev/null +++ b/springboot-seata/sbm-storage-service/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/springboot-seata/sbm-storage-service/pom.xml b/springboot-seata/sbm-storage-service/pom.xml new file mode 100755 index 0000000..dc2305b --- /dev/null +++ b/springboot-seata/sbm-storage-service/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.10.RELEASE + + + com.gf + sbm-storage-service + 0.0.1-SNAPSHOT + sbm-storage-service + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + io.seata + seata-spring-boot-starter + 1.0.0 + + + org.projectlombok + lombok + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.0 + + + mysql + mysql-connector-java + runtime + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/SbmStorageServiceApplication.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/SbmStorageServiceApplication.java new file mode 100755 index 0000000..7588a82 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/SbmStorageServiceApplication.java @@ -0,0 +1,14 @@ +package com.gf; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(scanBasePackages = "com.gf" , exclude = DataSourceAutoConfiguration.class) +public class SbmStorageServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(SbmStorageServiceApplication.class, args); + } + +} diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/config/DataSourceConfig.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/config/DataSourceConfig.java new file mode 100755 index 0000000..593c7e2 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/config/DataSourceConfig.java @@ -0,0 +1,24 @@ +package com.gf.config; + +import com.alibaba.druid.pool.DruidDataSource; +import io.seata.rm.datasource.DataSourceProxy; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceConfig { + + @Bean + @ConfigurationProperties(prefix = "spring.datasource") + public DataSource druidDataSource() { + DruidDataSource druidDataSource = new DruidDataSource(); + return druidDataSource; + } +} \ No newline at end of file diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java new file mode 100755 index 0000000..b8c3778 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/config/SeataRestTemplateAutoConfiguration.java @@ -0,0 +1,47 @@ +package com.gf.config; + +import com.gf.interceptor.SeataRestTemplateInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +@Configuration +public class SeataRestTemplateAutoConfiguration { + @Autowired( + required = false + ) + private Collection restTemplates; + @Autowired + private SeataRestTemplateInterceptor seataRestTemplateInterceptor; + + public SeataRestTemplateAutoConfiguration() { + } + + @Bean + public SeataRestTemplateInterceptor seataRestTemplateInterceptor() { + return new SeataRestTemplateInterceptor(); + } + + @PostConstruct + public void init() { + if (this.restTemplates != null) { + Iterator var1 = this.restTemplates.iterator(); + + while (var1.hasNext()) { + RestTemplate restTemplate = (RestTemplate) var1.next(); + List interceptors = new ArrayList(restTemplate.getInterceptors()); + interceptors.add(this.seataRestTemplateInterceptor); + restTemplate.setInterceptors(interceptors); + } + } + + } +} diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/controller/StorageController.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/controller/StorageController.java new file mode 100755 index 0000000..07f80ac --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/controller/StorageController.java @@ -0,0 +1,26 @@ +package com.gf.controller; + +import com.gf.entity.Storage; +import com.gf.service.StorageService; +import io.seata.core.context.RootContext; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.sql.SQLException; + +@RequestMapping("/api/storage") +@RestController +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class StorageController { + + + private final StorageService storageService; + + @GetMapping(value = "/deduct") + public void deduct(@RequestParam String commodityCode, @RequestParam Integer count) throws SQLException { + System.out.println("storage XID " + RootContext.getXID()); + storageService.deduct(commodityCode, count); + } + +} \ No newline at end of file diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/entity/Storage.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/entity/Storage.java new file mode 100755 index 0000000..8ca11b3 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/entity/Storage.java @@ -0,0 +1,15 @@ +package com.gf.entity; + +import lombok.*; + +@Builder +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class Storage { + private Integer id; + private String commodityCode; + private Integer count; +} diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/filter/SeataFilter.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/filter/SeataFilter.java new file mode 100755 index 0000000..cf6e77f --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/filter/SeataFilter.java @@ -0,0 +1,43 @@ +package com.gf.filter; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Component; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@Component +public class SeataFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) servletRequest; + String xid = req.getHeader(RootContext.KEY_XID.toLowerCase()); + boolean isBind = false; + if (StringUtils.isNotBlank(xid)) { + RootContext.bind(xid); + isBind = true; + } + try { + filterChain.doFilter(servletRequest, servletResponse); + } finally { + if (isBind) { + RootContext.unbind(); + } + } + } + + @Override + public void destroy() { + } +} diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java new file mode 100755 index 0000000..ac547a0 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/interceptor/SeataRestTemplateInterceptor.java @@ -0,0 +1,27 @@ +package com.gf.interceptor; + +import io.seata.core.context.RootContext; +import org.apache.commons.lang.StringUtils; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.support.HttpRequestWrapper; + +import java.io.IOException; + +public class SeataRestTemplateInterceptor implements ClientHttpRequestInterceptor { + public SeataRestTemplateInterceptor() { + } + + @Override + public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest); + String xid = RootContext.getXID(); + if (StringUtils.isNotEmpty(xid)) { + requestWrapper.getHeaders().add(RootContext.KEY_XID, xid); + } + + return clientHttpRequestExecution.execute(requestWrapper, bytes); + } +} diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/mapper/StorageMapper.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/mapper/StorageMapper.java new file mode 100755 index 0000000..3e71ab4 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/mapper/StorageMapper.java @@ -0,0 +1,23 @@ +package com.gf.mapper; + +import com.gf.entity.Storage; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface StorageMapper { + + Storage selectById(@Param("id") Integer id); + + Storage findByCommodityCode(@Param("commodityCode") String commodityCode); + + int updateById(Storage record); + + void insert(Storage record); + + void insertBatch(List records); + + int updateBatch(@Param("list") List ids, @Param("commodityCode") String commodityCode); +} diff --git a/springboot-seata/sbm-storage-service/src/main/java/com/gf/service/StorageService.java b/springboot-seata/sbm-storage-service/src/main/java/com/gf/service/StorageService.java new file mode 100755 index 0000000..f980824 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/java/com/gf/service/StorageService.java @@ -0,0 +1,23 @@ +package com.gf.service; + +import com.gf.entity.Storage; +import com.gf.mapper.StorageMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor(onConstructor_={@Autowired}) +public class StorageService { + + private final StorageMapper storageMapper; + + + public void deduct(String commodityCode, int count) { + Storage storage = storageMapper.findByCommodityCode(commodityCode); + storage.setCount(storage.getCount() - count); + storageMapper.updateById(storage); + } + + +} diff --git a/springboot-seata/sbm-storage-service/src/main/resources/application.properties b/springboot-seata/sbm-storage-service/src/main/resources/application.properties new file mode 100755 index 0000000..961ee43 --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/resources/application.properties @@ -0,0 +1,10 @@ +spring.application.name=storage-service +server.port=8083 +spring.datasource.url=jdbc:mysql://172.16.2.101:3306/db_seata?useSSL=false&serverTimezone=UTC +spring.datasource.username=root +spring.datasource.password=123456 +seata.tx-service-group=my_test_tx_group +mybatis.mapper-locations=classpath*:mapper/*Mapper.xml +logging.level.io.seata=info +seata.service.grouplist=172.16.2.101:8091 +logging.level.io.seata.samples.storage.persistence.StorageMapper=debug diff --git a/springboot-seata/sbm-storage-service/src/main/resources/mapper/StorageMapper.xml b/springboot-seata/sbm-storage-service/src/main/resources/mapper/StorageMapper.xml new file mode 100755 index 0000000..1449b8e --- /dev/null +++ b/springboot-seata/sbm-storage-service/src/main/resources/mapper/StorageMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + update storage_tbl set count = #{count,jdbcType=INTEGER} + WHERE id = #{id} + + + + insert into storage_tbl (commodity_code, count) + values (#{storage.commodityCode}, #{storage.count}) + + + + insert into storage_tbl (commodity_code, count) + values + + (#{item.commodityCode,jdbcType=VARCHAR}, #{item.count,jdbcType=INTEGER}) + + + + + update storage_tbl set count = 100 + WHERE id IN + + #{item} + + and commodity_code = #{commodityCode,jdbcType=VARCHAR} + + \ No newline at end of file diff --git a/springboot-seata/sbm-storage-service/src/test/java/com/gf/SbmStorageServiceApplicationTests.java b/springboot-seata/sbm-storage-service/src/test/java/com/gf/SbmStorageServiceApplicationTests.java new file mode 100755 index 0000000..e69de29 diff --git a/springboot-security-oauth2/src/main/java/com/gf/config/AuthorizationServerConfiguration.java b/springboot-security-oauth2/src/main/java/com/gf/config/AuthorizationServerConfiguration.java index 6c60339..4463400 100644 --- a/springboot-security-oauth2/src/main/java/com/gf/config/AuthorizationServerConfiguration.java +++ b/springboot-security-oauth2/src/main/java/com/gf/config/AuthorizationServerConfiguration.java @@ -63,26 +63,9 @@ public TokenStore tokenStore() { @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { - /** - * 配置oauth2服务跨域 - */ - CorsConfigurationSource source = new CorsConfigurationSource() { - @Override - public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { - CorsConfiguration corsConfiguration = new CorsConfiguration(); - corsConfiguration.addAllowedHeader("*"); - corsConfiguration.addAllowedOrigin(request.getHeader( HttpHeaders.ORIGIN)); - corsConfiguration.addAllowedMethod("*"); - corsConfiguration.setAllowCredentials(true); - corsConfiguration.setMaxAge(3600L); - return corsConfiguration; - } - }; - - security.tokenKeyAccess("permitAll()") + security.tokenKeyAccess("permitAll()") .checkTokenAccess("permitAll()") - .allowFormAuthenticationForClients() - .addTokenEndpointAuthenticationFilter(new CorsFilter(source)); + .allowFormAuthenticationForClients(); } @Override diff --git a/springboot-security-oauth2/src/main/java/com/gf/config/MyFilterSecurityInterceptor.java b/springboot-security-oauth2/src/main/java/com/gf/config/MyFilterSecurityInterceptor.java index a260438..5169676 100644 --- a/springboot-security-oauth2/src/main/java/com/gf/config/MyFilterSecurityInterceptor.java +++ b/springboot-security-oauth2/src/main/java/com/gf/config/MyFilterSecurityInterceptor.java @@ -14,6 +14,8 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -32,13 +34,20 @@ public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionM @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain); - invoke(fi); + HttpServletResponse response = (HttpServletResponse)servletResponse; + HttpServletRequest request = (HttpServletRequest)servletRequest; + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); + response.setHeader("Access-Control-Allow-Headers", ":x-requested-with,content-type"); + filterChain.doFilter(servletRequest,servletResponse); + if (!request.getRequestURI().equals("/oauth/token")) { + invoke(fi); + } + } public void invoke(FilterInvocation fi) throws IOException, ServletException { - InterceptorStatusToken token = super.beforeInvocation(fi); try { //执行下一个拦截器