├── .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 | --------------------------------------------------------------------------------