├── .gitattributes
├── .gitignore
├── README.md
├── pom.xml
├── sc-consumer
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── nutcracker
│ │ └── provider
│ │ ├── ConsumerApplication.java
│ │ └── web
│ │ └── controller
│ │ └── DemoApiController.java
│ └── resources
│ ├── META-INF
│ └── spring.factories
│ ├── application.yml
│ └── public
│ └── favicon.ico
├── sc-gateway
├── .gitignore
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── nutcarcker
│ │ │ └── gateway
│ │ │ ├── GatewayApplication.java
│ │ │ └── config
│ │ │ └── CorsConfig.java
│ └── resources
│ │ └── application.yml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── scgateway
│ └── ScGatewayApplicationTests.java
├── sc-openfeign
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── nutcracker
│ └── openfeign
│ ├── client
│ ├── api
│ │ └── DemoApiFeignClient.java
│ └── response
│ │ ├── BaseResponse.java
│ │ └── DemoApi.java
│ ├── constant
│ └── ProviderConstant.java
│ ├── exception
│ └── BusinessException.java
│ ├── fallback
│ └── DemoApiFeignClientFallback.java
│ └── okhttp
│ ├── OkHttpConfig.java
│ └── OkHttpLogInterceptor.java
└── sc-provider
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── nutcracker
│ │ └── provider
│ │ ├── ProviderApplication.java
│ │ ├── client
│ │ └── impl
│ │ │ └── DemoApiFeignClientImpl.java
│ │ └── exception
│ │ └── ProviderException.java
└── resources
│ ├── META-INF
│ └── spring.factories
│ ├── application.yml
│ └── public
│ └── favicon.ico
└── test
└── java
└── com
└── nutcracker
└── provider
└── Test.java
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-language=Java
2 | *.css linguist-language=Java
3 | *.html linguist-language=Java
4 | *.ftl linguist-language=Java
5 | *.FreeMarker linguist-language=Java
6 | *.freemarker linguist-language=Java
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## maven
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .springBeans
10 | .sts4-cache
11 |
12 | ### IntelliJ IDEA ###
13 | .idea
14 | *.iws
15 | *.iml
16 | *.ipr
17 | /out/
18 |
19 | ### NetBeans ###
20 | /nbproject/private/
21 | /nbbuild/
22 | /dist/
23 | /nbdist/
24 | /.nb-gradle/
25 | build/
26 | !**/src/main/**/build/
27 | !**/src/test/**/build/
28 |
29 | ### VS Code ###
30 | .vscode/
31 |
32 | ## Eclipse Core
33 | .project
34 | .classpath
35 | .settings
36 |
37 | # External tool builders
38 | .externalToolBuilers/
39 |
40 | # Locally stored "Eclipse launch configurations"
41 | *.launch
42 |
43 | # CDT-specific
44 | .cproject
45 |
46 | # Java annotation processor (APT)
47 | .factorypath
48 |
49 | # PDT-specific
50 | .buildpath
51 |
52 | # TeXlipse plugin
53 | .texlipse
54 |
55 | ## Mac
56 | .DS_Store
57 |
58 | ## SVN
59 | .svn
60 | catalina.base_IS_UNDEFINED
61 |
62 | ## rebel
63 | rebel-remote.xml
64 | rebel.xml
65 |
66 | ## log
67 | logs
68 | *.log
69 |
70 | ## other
71 | dubbo-cache
72 | dubbo-cache.lock
73 | docs
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sc 介绍 #
2 |
3 | `它是一个基于SpringCloud的分布式服务示例项目`
4 |
5 |
6 | 使用组件列表:
7 | 注册中心:nacos,替代方案eureka、consul、zookeeper
8 | 配置中心: nacos ,替代方案sc config、consul config
9 | 调用:feign,替代方案:resttempate
10 | 熔断:sentinel、,替代方案:Resilience4j
11 | 熔断监控:sentinel dashboard
12 | 负载均衡:sc loadbalancer
13 | 网关:spring cloud gateway
14 | 链路:spring cloud sleuth+zipkin,替代方案:skywalking等
15 |
16 |
17 | #### 包含工程有:
18 | * sc-consumer:client端,即consumer服务消费者。
19 | * sc-openfeign:SpringCloud OpenFeign,声明的接口,采用的是Nacos作为注册中心。
20 | * sc-provider:server端,即provider服务提供端,端口是随机分配的,可以启动多个服务对ribbon验证服务负载
21 |
22 | #### 示例启动
23 |
24 | * 按顺序依次启动项目工程: sc-provider、sc-consumer
25 |
26 | * 访问 sc-consumer 测试验证
27 | * 浏览器访问 [http://localhost:9999/diff/2](http://localhost:9999/diff/2)
28 |
29 | [GitHub](https://github.com/infowangxin) [issues](https://github.com/infowangxin/sc/issues)
30 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.nutcracker
8 | sc
9 | 2022.4.20-SNAPSHOT
10 | pom
11 | https://github.com/infowangxin/sc
12 |
13 | ${project.artifactId}
14 | 微服务示例工程
15 |
16 |
17 | sc-consumer
18 | sc-gateway
19 | sc-openfeign
20 | sc-provider
21 |
22 |
23 |
24 |
25 | The Apache Software License, Version 2.0
26 | http://www.apache.org/licenses/LICENSE-2.0.txt
27 | repo
28 |
29 |
30 | 2022
31 |
32 |
33 |
34 |
35 | scm:git:git@github.com:infowangxin/sc
36 |
37 |
38 |
39 | scm:git:git@github.com:infowangxin/sc
40 |
41 |
42 | https://github.com/infowangxin/sc
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 胡桃夹子
51 |
52 | https://github.com/infowangxin
53 |
54 |
55 |
56 |
57 | 胡桃夹子
58 | infowangxin@139.com
59 |
60 |
61 |
62 |
63 |
64 |
65 | github
66 |
67 | https://github.com/infowangxin/sc/issues
68 |
69 |
70 |
71 | 8
72 | 8
73 | 1.8
74 | UTF-8
75 | UTF-8
76 | true
77 | true
78 |
79 |
80 | 2.6.7
81 |
82 | 2021.0.2
83 |
84 |
85 | 2021.1
86 | 3.1.1
87 |
88 |
89 |
90 |
91 |
92 | com.nutcracker
93 | sc-openfeign
94 | ${project.version}
95 |
96 |
97 |
98 |
99 | org.springframework.boot
100 | spring-boot-dependencies
101 | ${spring-boot.version}
102 | pom
103 | import
104 |
105 |
106 |
107 |
108 | org.springframework.cloud
109 | spring-cloud-dependencies
110 | ${spring-cloud.version}
111 | pom
112 | import
113 |
114 |
115 |
116 |
117 | org.springframework.cloud
118 | spring-cloud-starter-bootstrap
119 | ${spring-cloud.bootstrap.version}
120 |
121 |
122 |
123 |
124 | com.alibaba.cloud
125 | spring-cloud-alibaba-dependencies
126 | ${spring-cloud-alibaba.version}
127 | pom
128 | import
129 |
130 |
131 |
132 |
133 | io.github.openfeign
134 | feign-okhttp
135 | 11.8
136 |
137 |
138 |
139 |
140 | org.apache.commons
141 | commons-collections4
142 | 4.4
143 |
144 |
145 |
146 |
147 | com.alibaba.fastjson2
148 | fastjson2
149 | 2.0.1
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/sc-consumer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | com.nutcracker
7 | sc
8 | 2022.4.20-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | sc-consumer
13 | jar
14 |
15 | ${project.artifactId}
16 | 微服务示例工程,openfeign
17 |
18 |
19 |
20 | com.nutcracker
21 | sc-openfeign
22 |
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-web
28 |
29 |
30 | com.alibaba.cloud
31 | spring-cloud-starter-alibaba-nacos-discovery
32 |
33 |
34 | org.springframework.cloud
35 | spring-cloud-starter-openfeign
36 |
37 |
38 |
39 | org.springframework.cloud
40 | spring-cloud-starter-loadbalancer
41 |
42 |
43 |
44 | com.alibaba.cloud
45 | spring-cloud-starter-alibaba-sentinel
46 |
47 |
48 |
49 | com.fasterxml.jackson.dataformat
50 | jackson-dataformat-xml
51 |
52 |
53 |
54 |
55 | com.alibaba.cloud
56 | spring-cloud-alibaba-sentinel-datasource
57 |
58 |
59 | com.alibaba.csp
60 | sentinel-datasource-nacos
61 |
62 |
63 |
64 |
65 | io.github.openfeign
66 | feign-okhttp
67 |
68 |
69 |
70 |
71 | com.alibaba.fastjson2
72 | fastjson2
73 |
74 |
75 |
76 |
77 |
78 |
79 | ${project.artifactId}
80 |
81 |
82 | org.springframework.boot
83 | spring-boot-maven-plugin
84 |
85 |
86 |
87 |
88 | repackage
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/sc-consumer/src/main/java/com/nutcracker/provider/ConsumerApplication.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.provider;
2 |
3 |
4 | import com.nutcracker.openfeign.okhttp.OkHttpConfig;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.boot.SpringApplication;
8 | import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
9 | import org.springframework.boot.autoconfigure.SpringBootApplication;
10 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
11 | import org.springframework.cloud.openfeign.EnableFeignClients;
12 |
13 | /**
14 | * start application
15 | * EnableDiscoveryClient 表明是一个Nacos客户端,该注解是 SpringCloud 提供的原生注解
16 | *
17 | * @author 胡桃夹子
18 | * @date 2022/4/20 21:06
19 | */
20 | @ImportAutoConfiguration(classes = {OkHttpConfig.class})
21 | @EnableFeignClients(basePackages = "com.nutcarcker.openfeign")
22 | @EnableDiscoveryClient
23 | @SpringBootApplication
24 | public class ConsumerApplication {
25 |
26 | private static final Logger LOG = LoggerFactory.getLogger(ConsumerApplication.class);
27 |
28 | public static void main(String[] args) {
29 | SpringApplication.run(ConsumerApplication.class, args);
30 | LOG.info(">>>>>>>>>>>>>>>>>>>> start successful <<<<<<<<<<<<<<<<<<<<");
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/sc-consumer/src/main/java/com/nutcracker/provider/web/controller/DemoApiController.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.provider.web.controller;
2 |
3 | import com.nutcracker.openfeign.client.api.DemoApiFeignClient;
4 | import com.nutcracker.openfeign.client.response.BaseResponse;
5 | import com.nutcracker.openfeign.client.response.DemoApi;
6 | import com.nutcracker.openfeign.exception.BusinessException;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.web.bind.annotation.GetMapping;
11 | import org.springframework.web.bind.annotation.PathVariable;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | /**
15 | * @author 胡桃夹子
16 | * @date 2022-01-21 18:17
17 | */
18 | @RestController
19 | public class DemoApiController {
20 |
21 | private static final Logger LOG = LoggerFactory.getLogger(DemoApiController.class);
22 |
23 | @Autowired
24 | private DemoApiFeignClient demoApiFeignClient;
25 |
26 | @GetMapping("diff/{input}")
27 | public BaseResponse diff(@PathVariable Integer input) {
28 | LOG.info("# diff input={}", input);
29 | BaseResponse result = null;
30 | try {
31 | result = demoApiFeignClient.getDiff(input);
32 | } catch (BusinessException e) {
33 | result = new BaseResponse<>(500, e.getMessage());
34 | LOG.error("# BusinessException {}", result);
35 | } catch (Throwable e) {
36 | result = new BaseResponse<>(500, e.getMessage());
37 | LOG.error("# Exception {}", result);
38 | }
39 | LOG.debug("# {}", result);
40 | return result;
41 | }
42 |
43 | @GetMapping("msg/{input}")
44 | public BaseResponse msg(@PathVariable Integer input) {
45 | LOG.info("# msg input={}", input);
46 | BaseResponse result;
47 | try {
48 | result = demoApiFeignClient.getMessage(input);
49 | } catch (BusinessException e) {
50 | result = new BaseResponse<>(500, e.getMessage());
51 | LOG.error("# BusinessException {}", result);
52 | } catch (Throwable e) {
53 | result = new BaseResponse<>(500, e.getMessage());
54 | LOG.error("# Exception {}", result);
55 | }
56 | return result;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/sc-consumer/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infowangxin/sc/53ef6ee09fd368ac3912a3bbd0445d34c3b9b05f/sc-consumer/src/main/resources/META-INF/spring.factories
--------------------------------------------------------------------------------
/sc-consumer/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9999
3 | spring:
4 | application:
5 | name: consumer
6 | main:
7 | allow-bean-definition-overriding: true # 解决bean重复定义。设置为true,后定义bean覆盖之前定义相同名称的bean。springboot2.0.4开始支持,默认为rue;springboot2.1.0开始默认false
8 | allow-circular-references: true # 开启循环依赖,从springboot2.6.0开始,默认禁止循环依赖
9 | cloud:
10 | nacos:
11 | discovery:
12 | server-addr: nutcracker.nacos
13 | namespace: fda2eeb2-8978-46b0-9f45-9ebaf141a3e6 # nutcracker
14 | sentinel:
15 | transport:
16 | port: 8719
17 | dashboard: 127.0.0.1:8843
18 | datasource: #配置sentinel持久化数据源(nacos)
19 | ds1:
20 | nacos:
21 | server-addr: nutcracker.nacos
22 | dataId: nutcracker
23 | groupId: DEFAULT_GROUP
24 | data-type: json
25 | rule-type: flow
26 | feign:
27 | compression:
28 | request:
29 | # 压缩支持的MIME类型
30 | mime-types: text/xml,application/xml,application/json
31 | # 开启请求数据的压缩功能
32 | enabled: true
33 | # 数据压缩下限 1024标识传输数据大于1024 才会进行数据压缩(最小压缩值标准)
34 | min-request-size: 1024
35 | # 开启响应数据的压缩功能
36 | response:
37 | enabled: true
38 | okhttp:
39 | enabled: true
40 | sentinel:
41 | enabled: true
42 |
43 | logging:
44 | pattern:
45 | console: "[%date{HH:mm:ss.SSS}] [%thread] %-5level %logger %line - %msg%n"
46 | level:
47 | root: INFO
48 | org.nutcracker: DEBUG
49 | org.springframework.web: TRACE
50 | org.springframework.http: TRACE
51 | org.springframework.security: TRACE
52 | org.springframework.cloud.gateway: TRACE
53 | org.springframework.security.jwt: TRACE
54 | # org.springframework.jdbc.core.JdbcTemplate: DEBUG
55 | # org.springframework.jdbc.core.StatementCreatorUtils: trace
56 | # org.apache.ibatis.jdbc.ScriptRunner: DEBUG
57 | # java.sql.Connection: DEBUG
58 | # java.sql.Statement: DEBUG
59 | # java.sql.PreparedStatement: DEBUG
60 |
--------------------------------------------------------------------------------
/sc-consumer/src/main/resources/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infowangxin/sc/53ef6ee09fd368ac3912a3bbd0445d34c3b9b05f/sc-consumer/src/main/resources/public/favicon.ico
--------------------------------------------------------------------------------
/sc-gateway/.gitignore:
--------------------------------------------------------------------------------
1 | ## maven
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .springBeans
10 | .sts4-cache
11 |
12 | ### IntelliJ IDEA ###
13 | .idea
14 | *.iws
15 | *.iml
16 | *.ipr
17 | /out/
18 |
19 | ### NetBeans ###
20 | /nbproject/private/
21 | /nbbuild/
22 | /dist/
23 | /nbdist/
24 | /.nb-gradle/
25 | build/
26 | !**/src/main/**/build/
27 | !**/src/test/**/build/
28 |
29 | ### VS Code ###
30 | .vscode/
31 |
32 | ## Eclipse Core
33 | .project
34 | .classpath
35 | .settings
36 |
37 | # External tool builders
38 | .externalToolBuilers/
39 |
40 | # Locally stored "Eclipse launch configurations"
41 | *.launch
42 |
43 | # CDT-specific
44 | .cproject
45 |
46 | # Java annotation processor (APT)
47 | .factorypath
48 |
49 | # PDT-specific
50 | .buildpath
51 |
52 | # TeXlipse plugin
53 | .texlipse
54 |
55 | ## Mac
56 | .DS_Store
57 |
58 | ## SVN
59 | .svn
60 | catalina.base_IS_UNDEFINED
61 |
62 | ## rebel
63 | rebel-remote.xml
64 | rebel.xml
65 |
66 | ## log
67 | logs
68 | *.log
69 |
70 | ## other
71 | dubbo-cache
72 | dubbo-cache.lock
73 | docs
74 |
--------------------------------------------------------------------------------
/sc-gateway/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | com.nutcracker
6 | sc
7 | 2022.4.20-SNAPSHOT
8 |
9 | 4.0.0
10 | sc-gateway
11 | 0.0.1-SNAPSHOT
12 | sc-gateway
13 | sc-gateway
14 |
15 |
16 |
17 | org.springframework.cloud
18 | spring-cloud-starter-gateway
19 |
20 |
21 |
22 | javax.servlet
23 | javax.servlet-api
24 | provided
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-test
30 | test
31 |
32 |
33 |
34 |
35 |
36 | ${project.artifactId}
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-maven-plugin
41 |
42 |
43 |
44 |
45 | repackage
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/sc-gateway/src/main/java/com/nutcarcker/gateway/GatewayApplication.java:
--------------------------------------------------------------------------------
1 | package com.nutcarcker.gateway;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 |
8 | /**
9 | * start application
10 | *
11 | * @author 胡桃夹子
12 | * @date 2022/6/2 08:50
13 | */
14 | @SpringBootApplication
15 | public class GatewayApplication {
16 |
17 | private static final Logger LOG = LoggerFactory.getLogger(GatewayApplication.class);
18 |
19 | public static void main(String[] args) {
20 | SpringApplication.run(GatewayApplication.class, args);
21 | LOG.info(">>>>>>>>>>>>>>>>>>>> start successful <<<<<<<<<<<<<<<<<<<<");
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/sc-gateway/src/main/java/com/nutcarcker/gateway/config/CorsConfig.java:
--------------------------------------------------------------------------------
1 | package com.nutcarcker.gateway.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.cors.CorsConfiguration;
6 | import org.springframework.web.cors.reactive.CorsWebFilter;
7 | import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
8 | import org.springframework.web.util.pattern.PathPatternParser;
9 |
10 | /**
11 | * 跨域配置
12 | *
13 | * @author 胡桃夹子
14 | * @date 2022/6/1 20:17
15 | */
16 | @Configuration
17 | public class CorsConfig {
18 |
19 | @Bean
20 | public CorsWebFilter corsFilter() {
21 | CorsConfiguration config = new CorsConfiguration();
22 | //允许跨域访问的域名,可填写具体域名,*代表允许所有访问
23 | config.addAllowedOrigin("*");
24 | //允许访问类型:get post 等,*代表所有类型
25 | config.addAllowedMethod("*");
26 | //允许任何头
27 | config.addAllowedHeader("*");
28 |
29 | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
30 | source.registerCorsConfiguration("/**", config);
31 | return new CorsWebFilter(source);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/sc-gateway/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8000
3 | servlet:
4 | context-path: /
5 | shutdown: graceful # 优雅停服务,在容器关闭时,web服务器将不再接收新请求,并将等待活动请求完成的缓冲期。从springboot2.3.0引入的新特性
6 | spring:
7 | application:
8 | name: sc-gateway
9 | cloud:
10 | gateway:
11 | discovery:
12 | locator:
13 | enabled: false
14 | lower-case-service-id: true
15 | routes:
16 | - id: sc-provider
17 | uri: la://nutcracker:8848
18 | predicates:
19 | - Path=/aplus-support-web/**
20 | - Method=POST,GET
21 | filters:
22 | - AddResponseHeader=From-Host,127.0.0.1:8882
23 | logging:
24 | pattern:
25 | console: "[%date{HH:mm:ss.SSS}] [%thread] %-5level %logger %line - %msg%n"
26 | level:
27 | root: INFO
28 | org.nutcracker: DEBUG
29 | org.springframework.web: TRACE
30 | org.springframework.http: TRACE
31 | org.springframework.security: TRACE
32 | org.springframework.cloud.gateway: TRACE
33 | org.springframework.security.jwt: TRACE
34 | # org.springframework.jdbc.core.JdbcTemplate: DEBUG
35 | # org.springframework.jdbc.core.StatementCreatorUtils: trace
36 | # org.apache.ibatis.jdbc.ScriptRunner: DEBUG
37 | # java.sql.Connection: DEBUG
38 | # java.sql.Statement: DEBUG
39 | # java.sql.PreparedStatement: DEBUG
40 |
--------------------------------------------------------------------------------
/sc-gateway/src/test/java/com/example/scgateway/ScGatewayApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.scgateway;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class ScGatewayApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/sc-openfeign/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | com.nutcracker
7 | sc
8 | 2022.4.20-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | sc-openfeign
13 | jar
14 |
15 | ${project.artifactId}
16 | 微服务示例工程,接口
17 |
18 |
19 |
20 | org.springframework.cloud
21 | spring-cloud-starter-openfeign
22 |
23 |
24 |
25 | io.github.openfeign
26 | feign-okhttp
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/client/api/DemoApiFeignClient.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.client.api;
2 |
3 | import com.nutcracker.openfeign.client.response.BaseResponse;
4 | import com.nutcracker.openfeign.client.response.DemoApi;
5 | import com.nutcracker.openfeign.constant.ProviderConstant;
6 | import com.nutcracker.openfeign.exception.BusinessException;
7 | import com.nutcracker.openfeign.fallback.DemoApiFeignClientFallback;
8 | import org.springframework.cloud.openfeign.FeignClient;
9 | import org.springframework.stereotype.Service;
10 | import org.springframework.web.bind.annotation.GetMapping;
11 | import org.springframework.web.bind.annotation.RequestParam;
12 |
13 | /**
14 | * 示例接口
15 | *
16 | * @author 胡桃夹子
17 | * @date 2022-04-20 21:45
18 | */
19 | @Service
20 | @FeignClient(name = ProviderConstant.PROVIDER, fallback = DemoApiFeignClientFallback.class)
21 | public interface DemoApiFeignClient {
22 |
23 | @GetMapping("/demoApi/getDiff")
24 | public BaseResponse getDiff(@RequestParam("value") Integer value);
25 |
26 | @GetMapping("/demoApi/getMessage")
27 | public BaseResponse getMessage(@RequestParam("value") Integer value) throws BusinessException;
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/client/response/BaseResponse.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.client.response;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 响应结果包装类
7 | *
8 | * @author 胡桃夹子
9 | * @date 2022-05-03 16:40
10 | */
11 | public class BaseResponse implements Serializable {
12 | private static final long serialVersionUID = -4001308558105657575L;
13 |
14 | /**
15 | * 响应状态
16 | */
17 | private Integer status;
18 |
19 | /**
20 | * 响应描述
21 | */
22 | private String message;
23 |
24 | /**
25 | * 结果实体对象
26 | */
27 | private T body;
28 |
29 | public Integer getStatus() {
30 | return this.status;
31 | }
32 |
33 | public void setStatus(Integer status) {
34 | this.status = status;
35 | }
36 |
37 | public String getMessage() {
38 | return this.message;
39 | }
40 |
41 | public void setMessage(String message) {
42 | this.message = message;
43 | }
44 |
45 | public T getBody() {
46 | return this.body;
47 | }
48 |
49 | public void setBody(T body) {
50 | this.body = body;
51 | }
52 |
53 |
54 | public BaseResponse() {
55 |
56 | }
57 |
58 | public BaseResponse(Integer status, String message) {
59 | this.status = status;
60 | this.message = message;
61 | }
62 |
63 | public BaseResponse(Integer status, String message, T body) {
64 | this.status = status;
65 | this.message = message;
66 | this.body = body;
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/client/response/DemoApi.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.client.response;
2 |
3 | import java.io.Serializable;
4 |
5 |
6 | /**
7 | * 消息实体对象
8 | *
9 | * @author 胡桃夹子
10 | * @date 2022/1/24 10:00
11 | */
12 | public class DemoApi implements Serializable {
13 |
14 | private static final long serialVersionUID = 4732186081041434484L;
15 |
16 | /**
17 | * 应用名称
18 | */
19 | private String name;
20 |
21 | /**
22 | * 端口
23 | */
24 | private Integer port;
25 |
26 | /**
27 | * 差
28 | */
29 | private Integer diff;
30 |
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public void setName(String name) {
36 | this.name = name;
37 | }
38 |
39 | public Integer getPort() {
40 | return this.port;
41 | }
42 |
43 | public void setPort(Integer port) {
44 | this.port = port;
45 | }
46 |
47 | public Integer getDiff() {
48 | return diff;
49 | }
50 |
51 | public void setDiff(Integer diff) {
52 | this.diff = diff;
53 | }
54 |
55 | @Override
56 | public String toString() {
57 | String sb = getClass().getSimpleName() +
58 | " {" +
59 | "\"name\":\"" +
60 | name + '\"' +
61 | ",\"point\":" +
62 | port +
63 | ",\"diff\":" +
64 | diff +
65 | '}';
66 | return sb;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/constant/ProviderConstant.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.constant;
2 |
3 | /**
4 | * 常量类
5 | *
6 | * @author 胡桃夹子
7 | * @date 2022-04-24 20:31
8 | */
9 | public class ProviderConstant {
10 |
11 | private ProviderConstant() {
12 |
13 | }
14 |
15 | public static final String PROVIDER = "provider";
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/exception/BusinessException.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.exception;
2 |
3 | /**
4 | * 自定义异常类
5 | *
6 | * @author 胡桃夹子
7 | * @date 2020/2/21 18:08
8 | */
9 | public class BusinessException extends RuntimeException {
10 |
11 | private static final long serialVersionUID = 2248546206040115304L;
12 |
13 | private String errorCode;
14 |
15 | public BusinessException() {
16 |
17 | }
18 |
19 | public BusinessException(String message) {
20 | super(message);
21 | }
22 |
23 | public BusinessException(String errorCode, String message) {
24 | super(message);
25 | this.errorCode = errorCode;
26 | }
27 |
28 | public BusinessException(Throwable caused) {
29 | super(caused);
30 | }
31 |
32 | public String getErrorCode() {
33 | return errorCode;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/fallback/DemoApiFeignClientFallback.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.fallback;
2 |
3 | import com.nutcracker.openfeign.client.api.DemoApiFeignClient;
4 | import com.nutcracker.openfeign.client.response.DemoApi;
5 | import com.nutcracker.openfeign.client.response.BaseResponse;
6 | import com.nutcracker.openfeign.exception.BusinessException;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.stereotype.Component;
10 |
11 | /**
12 | * 示例接口 溶断处理
13 | *
14 | * @author 胡桃夹子
15 | * @date 2022-05-03 16:36
16 | */
17 | @Component
18 | public class DemoApiFeignClientFallback implements DemoApiFeignClient {
19 |
20 | private static final Logger LOG = LoggerFactory.getLogger(DemoApiFeignClientFallback.class);
21 |
22 | @Override
23 | public BaseResponse getDiff(Integer value) {
24 | LOG.error("# 请求异常 value=[{}]", value);
25 | return new BaseResponse<>(500, "from DemoApiFallback");
26 | }
27 |
28 | @Override
29 | public BaseResponse getMessage(Integer value) throws BusinessException {
30 | LOG.error("# 请求异常 value=[{}]", value);
31 | return new BaseResponse<>(500, "from DemoApiFallback");
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/okhttp/OkHttpConfig.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.okhttp;
2 |
3 | import okhttp3.ConnectionPool;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | import javax.net.ssl.HostnameVerifier;
8 | import javax.net.ssl.SSLContext;
9 | import javax.net.ssl.SSLSocketFactory;
10 | import javax.net.ssl.TrustManager;
11 | import javax.net.ssl.X509TrustManager;
12 | import java.security.KeyManagementException;
13 | import java.security.NoSuchAlgorithmException;
14 | import java.security.SecureRandom;
15 | import java.security.cert.CertificateException;
16 | import java.security.cert.X509Certificate;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * okhttp config
21 | *
22 | * @author 胡桃夹子
23 | * @date 2022-04-24 19:48
24 | */
25 | @Configuration
26 | public class OkHttpConfig {
27 |
28 | /**
29 | * 忽略证书校验
30 | *
31 | * @return 证书信任管理器
32 | */
33 | @Bean
34 | public X509TrustManager x509TrustManager() {
35 | return new X509TrustManager() {
36 | @Override
37 | public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
38 | }
39 |
40 | @Override
41 | public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
42 | }
43 |
44 | @Override
45 | public X509Certificate[] getAcceptedIssuers() {
46 | return new X509Certificate[0];
47 | }
48 | };
49 | }
50 |
51 | /**
52 | * 信任所有 SSL 证书
53 | *
54 | * @return
55 | */
56 | @Bean
57 | public SSLSocketFactory sslSocketFactory() {
58 | try {
59 | TrustManager[] trustManagers = new TrustManager[]{x509TrustManager()};
60 | SSLContext sslContext = SSLContext.getInstance("SSL");
61 | sslContext.init(null, trustManagers, new SecureRandom());
62 | return sslContext.getSocketFactory();
63 | } catch (NoSuchAlgorithmException | KeyManagementException e) {
64 | e.printStackTrace();
65 | }
66 | return null;
67 | }
68 |
69 | /**
70 | * 连接池配置
71 | *
72 | * @return 连接池
73 | */
74 | @Bean
75 | public ConnectionPool pool() {
76 | // 最大连接数、连接存活时间、存活时间单位(分钟)
77 | // max-connections: 200 # 默认值
78 | // max-connections-per-route: 50 # 默认值
79 | return new ConnectionPool(200, 5, TimeUnit.MINUTES);
80 | }
81 |
82 | @Bean
83 | public okhttp3.OkHttpClient okHttpClient() {
84 | return new okhttp3.OkHttpClient.Builder()
85 | // 读取超时时间
86 | .readTimeout(10, TimeUnit.SECONDS)
87 | // 连接超时时间
88 | .connectTimeout(10, TimeUnit.SECONDS)
89 | // 写超时时间
90 | .writeTimeout(10, TimeUnit.SECONDS)
91 | // 设置连接池
92 | //.connectionPool(new ConnectionPool())
93 | .connectionPool(pool())
94 | // 设置拦截器
95 | .addInterceptor(new OkHttpLogInterceptor())
96 | .build();
97 | }
98 |
99 |
100 | /**
101 | * 信任所有主机名
102 | *
103 | * @return 主机名校验
104 | */
105 | @Bean
106 | public HostnameVerifier hostnameVerifier() {
107 | return (s, sslSession) -> true;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/sc-openfeign/src/main/java/com/nutcracker/openfeign/okhttp/OkHttpLogInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.openfeign.okhttp;
2 |
3 | import okhttp3.Interceptor;
4 | import okhttp3.Request;
5 | import okhttp3.Response;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.io.IOException;
10 |
11 | /**
12 | * OKHTTP LOG 拦截器
13 | *
14 | * @author 胡桃夹子
15 | * @date 2022/4/25 16:54
16 | */
17 | public class OkHttpLogInterceptor implements Interceptor {
18 |
19 | private static final Logger LOG = LoggerFactory.getLogger(OkHttpLogInterceptor.class);
20 |
21 | @Override
22 | public Response intercept(Interceptor.Chain chain) throws IOException {
23 | //这个chain里面包含了request和response,所以你要什么都可以从这里拿
24 | Request request = chain.request();
25 |
26 | long t1 = System.nanoTime();
27 | LOG.info(String.format("#==> 发送请求: %s on %s%n%s", request.url(), chain.connection(), request.headers()));
28 |
29 | Response response = chain.proceed(request);
30 | long t2 = System.nanoTime();
31 | LOG.info(String.format("#<== 接收响应: %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers()));
32 | return response;
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/sc-provider/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | com.nutcracker
7 | sc
8 | 2022.4.20-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | sc-provider
13 | jar
14 |
15 | ${project.artifactId}
16 | 微服务示例工程,服务提供者
17 |
18 |
19 |
20 | com.nutcracker
21 | sc-openfeign
22 |
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-web
28 |
29 |
30 | com.alibaba.cloud
31 | spring-cloud-starter-alibaba-nacos-discovery
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | org.springframework.cloud
41 | spring-cloud-starter-loadbalancer
42 |
43 |
44 |
45 | com.alibaba.cloud
46 | spring-cloud-starter-alibaba-sentinel
47 |
48 |
49 |
50 | com.fasterxml.jackson.dataformat
51 | jackson-dataformat-xml
52 |
53 |
54 |
55 |
56 | com.alibaba.cloud
57 | spring-cloud-alibaba-sentinel-datasource
58 |
59 |
60 | com.alibaba.csp
61 | sentinel-datasource-nacos
62 |
63 |
64 |
65 |
66 | io.github.openfeign
67 | feign-okhttp
68 |
69 |
70 |
71 |
72 | org.apache.commons
73 | commons-lang3
74 |
75 |
76 | org.apache.commons
77 | commons-collections4
78 |
79 |
80 |
81 |
82 | com.alibaba.fastjson2
83 | fastjson2
84 |
85 |
86 |
87 |
88 | org.springframework.boot
89 | spring-boot-starter-test
90 | test
91 |
92 |
93 | org.springframework.boot
94 | spring-boot-devtools
95 | true
96 | runtime
97 |
98 |
99 |
100 |
101 |
102 | ${project.artifactId}
103 |
104 |
105 | org.springframework.boot
106 | spring-boot-maven-plugin
107 |
108 |
109 |
110 |
111 | repackage
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/sc-provider/src/main/java/com/nutcracker/provider/ProviderApplication.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.provider;
2 |
3 |
4 | import com.nutcracker.openfeign.okhttp.OkHttpConfig;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.boot.SpringApplication;
8 | import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
9 | import org.springframework.boot.autoconfigure.SpringBootApplication;
10 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
11 | import org.springframework.cloud.openfeign.EnableFeignClients;
12 |
13 | /**
14 | * start application
15 | *
16 | * @author 胡桃夹子
17 | * @date 2022/4/20 21:06
18 | */
19 | @ImportAutoConfiguration(classes = {OkHttpConfig.class})
20 | @SpringBootApplication
21 | @EnableFeignClients(basePackages = "com.nutcracker.openfeign")
22 | @EnableDiscoveryClient
23 | public class ProviderApplication {
24 |
25 | private static final Logger LOG = LoggerFactory.getLogger(ProviderApplication.class);
26 |
27 | public static void main(String[] args) {
28 | SpringApplication.run(ProviderApplication.class, args);
29 | LOG.info(">>>>>>>>>>>>>>>>>>>> sc-provider start successful <<<<<<<<<<<<<<<<<<<<");
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/sc-provider/src/main/java/com/nutcracker/provider/client/impl/DemoApiFeignClientImpl.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.provider.client.impl;
2 |
3 | import com.nutcracker.openfeign.client.api.DemoApiFeignClient;
4 | import com.nutcracker.openfeign.client.response.BaseResponse;
5 | import com.nutcracker.openfeign.client.response.DemoApi;
6 | import com.nutcracker.openfeign.exception.BusinessException;
7 | import com.nutcracker.provider.exception.ProviderException;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | /**
15 | * 示例接口实现类
16 | *
17 | * @author 胡桃夹子
18 | * @date 2022-04-24 19:37
19 | */
20 | @RestController
21 | public class DemoApiFeignClientImpl implements DemoApiFeignClient {
22 |
23 | private static final Logger LOG = LoggerFactory.getLogger(DemoApiFeignClientImpl.class);
24 |
25 | private static final int TOTAL = 10;
26 |
27 | @Value("${spring.application.name}")
28 | public String name;
29 |
30 | @Value("${server.port}")
31 | public Integer port;
32 |
33 | @Override
34 | @GetMapping("/demoApi/getDiff")
35 | public BaseResponse getDiff(Integer value) {
36 | if (null == value || value == 0) {
37 | throw new ProviderException("1001", "value is empty or zero");
38 | }
39 | int diff = TOTAL / value;
40 | DemoApi appEntity = new DemoApi();
41 | appEntity.setName(name);
42 | appEntity.setPort(port);
43 | appEntity.setDiff(diff);
44 |
45 | LOG.info("# appEntity={}", appEntity);
46 | return new BaseResponse<>(200, "success", appEntity);
47 | }
48 |
49 | @Override
50 | @GetMapping("/demoApi/getMessage")
51 | public BaseResponse getMessage(Integer value) throws BusinessException {
52 | try {
53 | // 此处线程睡眠11秒,为了验证fallback
54 | Thread.sleep(11000);
55 | return getDiff(value);
56 | } catch (InterruptedException e) {
57 | LOG.error("# Thread.sleep fail");
58 | throw new BusinessException(e);
59 | } catch (Exception e) {
60 | LOG.error("# Exception error msg {}", e.getMessage());
61 | throw new BusinessException("value error");
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/sc-provider/src/main/java/com/nutcracker/provider/exception/ProviderException.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.provider.exception;
2 |
3 | /**
4 | * 自定义异常类
5 | *
6 | * @author 胡桃夹子
7 | * @date 2020/2/24 18:08
8 | */
9 | public class ProviderException extends RuntimeException {
10 |
11 |
12 | private static final long serialVersionUID = 2248546206040115304L;
13 |
14 | private String errorCode;
15 |
16 | public ProviderException() {
17 |
18 | }
19 |
20 | public ProviderException(String message) {
21 | this.errorCode = errorCode;
22 | }
23 |
24 | public ProviderException(String errorCode, String message) {
25 | super(message);
26 | this.errorCode = errorCode;
27 | }
28 |
29 | public ProviderException(Throwable caused) {
30 | super(caused);
31 | }
32 |
33 | public String getErrorCode() {
34 | return errorCode;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/sc-provider/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infowangxin/sc/53ef6ee09fd368ac3912a3bbd0445d34c3b9b05f/sc-provider/src/main/resources/META-INF/spring.factories
--------------------------------------------------------------------------------
/sc-provider/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9001
3 | spring:
4 | application:
5 | name: provider
6 | main:
7 | allow-bean-definition-overriding: true # 解决bean重复定义。设置为true,后定义bean覆盖之前定义相同名称的bean。springboot2.0.4开始支持,默认为rue;springboot2.1.0开始默认false
8 | allow-circular-references: true # 开启循环依赖,从springboot2.6.0开始,默认禁止循环依赖
9 | cloud:
10 | nacos:
11 | discovery:
12 | server-addr: nutcracker.nacos
13 | namespace: nutcracker-nacos # nutcracker
14 | # namespace: fda2eeb2-8978-46b0-9f45-9ebaf141a3e6 # nutcracker
15 | sentinel:
16 | transport:
17 | # 默认8719端口,假如被占用则会从8179+1依次进行扫描,直至找到未被占用的端口
18 | port: 8719
19 | dashboard: 127.0.0.1:8843
20 | datasource: #配置sentinel持久化数据源(nacos)
21 | ds1:
22 | nacos:
23 | server-addr: nutcracker.nacos
24 | namespace: nutcracker-sentinel
25 | # namespace: 9c5f55ec-f9ad-482b-83d3-e4e9c26a9553
26 | dataId: nutcracker
27 | groupId: DEFAULT_GROUP
28 | data-type: json
29 | rule-type: flow
30 | feign:
31 | compression:
32 | request:
33 | # 压缩支持的MIME类型
34 | mime-types: text/xml,application/xml,application/json
35 | # 开启请求数据的压缩功能
36 | enabled: true
37 | # 数据压缩下限 1024标识传输数据大于1024 才会进行数据压缩(最小压缩值标准)
38 | min-request-size: 1024
39 | # 开启响应数据的压缩功能
40 | response:
41 | enabled: true
42 | okhttp:
43 | enabled: true
44 | sentinel:
45 | enabled: true
46 |
47 | logging:
48 | pattern:
49 | console: "[%date{HH:mm:ss.SSS}] [%thread] %-5level %logger %line - %msg%n"
50 | level:
51 | root: INFO
52 | org.nutcracker: DEBUG
53 | org.springframework.web: TRACE
54 | org.springframework.http: TRACE
55 | org.springframework.security: TRACE
56 | org.springframework.cloud.gateway: TRACE
57 | org.springframework.security.jwt: TRACE
58 | org.springframework.jdbc.core.JdbcTemplate: DEBUG
59 | org.springframework.jdbc.core.StatementCreatorUtils: trace
60 | org.apache.ibatis.jdbc.ScriptRunner: DEBUG
61 | java.sql.Connection: DEBUG
62 | java.sql.Statement: DEBUG
63 | java.sql.PreparedStatement: DEBUG
64 |
--------------------------------------------------------------------------------
/sc-provider/src/main/resources/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infowangxin/sc/53ef6ee09fd368ac3912a3bbd0445d34c3b9b05f/sc-provider/src/main/resources/public/favicon.ico
--------------------------------------------------------------------------------
/sc-provider/src/test/java/com/nutcracker/provider/Test.java:
--------------------------------------------------------------------------------
1 | package com.nutcracker.provider;
2 |
3 | import java.math.BigDecimal;
4 |
5 | /**
6 | * @author
7 | * @date 2022-05-24 16:05
8 | */
9 | public class Test {
10 | public static void main(String[] args) {
11 | BigDecimal bg = new BigDecimal(1.1199).setScale(4, BigDecimal.ROUND_HALF_DOWN);
12 | BigDecimal num1 = (bg.subtract(new BigDecimal(1).setScale(4, BigDecimal.ROUND_HALF_DOWN)));
13 | BigDecimal num2 = num1.divide(new BigDecimal(140),4).setScale(4, BigDecimal.ROUND_HALF_DOWN);
14 | System.out.println(num2);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------