├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── deploy_to_docker.sh ├── docker-compose.debug.yml ├── docker-compose.dev.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img └── home.png ├── mmall-domain-account ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── kay │ │ └── mmall │ │ └── account │ │ ├── AccountApplication.java │ │ ├── application │ │ ├── AccountApplicationService.java │ │ └── AddressApplicationService.java │ │ ├── controller │ │ ├── AccountController.java │ │ └── AddressController.java │ │ └── domain │ │ ├── AccountRepository.java │ │ ├── AddressRepository.java │ │ └── validation │ │ ├── AccountValidator.java │ │ ├── AuthenticatedAccount.java │ │ ├── NotConflictAccount.java │ │ └── UniqueAccount.java │ └── resources │ ├── application-test.yml │ ├── bootstrap.yml │ ├── db │ ├── data.sql │ └── schema.sql │ ├── public.cert │ ├── redisson-config.yml │ └── rsa.jks ├── mmall-domain-payment ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── kay │ │ └── mmall │ │ ├── PaymentApplication.java │ │ └── payment │ │ ├── controller │ │ ├── PaymentController.java │ │ └── SettlementController.java │ │ └── domain │ │ ├── Payment.java │ │ ├── Wallet.java │ │ ├── application │ │ └── PaymentApplicationService.java │ │ ├── client │ │ └── ProductServiceClient.java │ │ ├── repo │ │ ├── PaymentRepository.java │ │ └── WalletRepository.java │ │ ├── service │ │ ├── PaymentService.java │ │ └── WalletService.java │ │ └── validation │ │ ├── SettlementValidator.java │ │ └── ValidStock.java │ └── resources │ ├── application-test.yml │ ├── bootstrap.yml │ ├── db │ ├── data.sql │ └── schema.sql │ ├── public.cert │ └── redisson-config.yml ├── mmall-domain-security ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── kay │ │ └── mmall │ │ └── security │ │ ├── SecurityApplication.java │ │ ├── configuration │ │ ├── AuthenticationServerConfiguration.java │ │ ├── AuthorizationServerConfiguration.java │ │ └── WebSecurityConfiguration.java │ │ └── provider │ │ ├── PreAuthenticatedAuthenticationProvider.java │ │ ├── RSA256JWTAccessToken.java │ │ └── UsernamePasswordAuthenticationProvider.java │ └── resources │ ├── application-test.yml │ ├── bootstrap.yml │ ├── public.cert │ └── rsa.jks ├── mmall-domain-warehouse ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── kay │ │ └── mmall │ │ └── warehouse │ │ ├── WarehouseApplication.java │ │ ├── application │ │ └── ProductApplicationService.java │ │ ├── controller │ │ ├── AdvertisementController.java │ │ └── ProductController.java │ │ └── domain │ │ ├── Advertisement.java │ │ ├── AdvertisementRepository.java │ │ ├── ProductRepository.java │ │ ├── ProductService.java │ │ ├── StockpileRepository.java │ │ └── StockpileService.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ ├── db │ ├── data.sql │ └── schema.sql │ ├── public.cert │ └── redisson-config.yml ├── mmall-lib-infrastructure ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── github │ └── kay │ └── mmall │ ├── domain │ ├── BaseEntity.java │ ├── account │ │ ├── Account.java │ │ └── Address.java │ ├── product │ │ ├── DeliveredStatus.java │ │ ├── Product.java │ │ ├── Specification.java │ │ └── Stockpile.java │ └── security │ │ ├── AccountServiceClient.java │ │ ├── AuthenticAccount.java │ │ ├── AuthenticAccountDetailsService.java │ │ ├── AuthenticAccountRepository.java │ │ ├── GrantType.java │ │ ├── Role.java │ │ └── Scope.java │ ├── dto │ └── Settlement.java │ └── infrasucture │ ├── CROSFilter.java │ ├── EncoderConfiguration.java │ ├── common │ ├── CodedMessage.java │ ├── CommonResponse.java │ ├── ExceptionControllerAdvice.java │ └── ResourceNotFoundException.java │ ├── configuration │ ├── FeignConfiguration.java │ └── JPAConfiguration.java │ ├── lock │ ├── LockAutoConfiguration.java │ ├── LockOperationException.java │ ├── LockService.java │ ├── LockServiceDefault.java │ ├── LockServiceWithRedisson.java │ └── RedissonProperties.java │ ├── redis │ ├── RedisConfiguration.java │ ├── RedisKeyExpirationHandler.java │ ├── RedisKeyExpirationHandlerManager.java │ └── RedisKeyExpirationListener.java │ └── security │ ├── JWTAccessToken.java │ ├── JWTAccessTokenService.java │ ├── OAuthClientDetailsService.java │ ├── RSA256PublicJWTAccessToken.java │ └── ResourceServerConfiguration.java ├── mmall-platform-configuration ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── kay │ │ └── mmall │ │ └── ConfigurationApplication.java │ └── resources │ ├── application.yml │ └── configurations │ ├── account.yml │ ├── gateway.yml │ ├── payment.yml │ ├── registry.yml │ ├── security.yml │ └── warehouse.yml ├── mmall-platform-gateway ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── kay │ │ └── mmall │ │ └── GatewayApplication.java │ └── resources │ ├── bootstrap.yml │ └── static │ ├── index.html │ └── static │ ├── board │ ├── gitalk.css │ ├── gitalk.html │ └── gitalk.min.js │ ├── carousel │ ├── ai.png │ ├── banner1.jpg │ ├── banner2.jpg │ ├── banner3.jpg │ ├── banner4.jpg │ ├── banner5.jpg │ ├── fenix.png │ ├── fenix2.png │ └── jvm3.png │ ├── cover │ ├── product0.jpg │ ├── product1.jpg │ ├── product2.jpg │ ├── product3.jpg │ ├── product4.jpg │ ├── product5.jpg │ └── product6.jpg │ ├── css │ └── app.b5d124c9dd22d7f1d55bbcec57fb027d.css │ ├── desc │ ├── OSGi.jpg │ ├── ai.jpg │ ├── fenix.jpg │ ├── jvm2.jpg │ ├── jvm3.jpg │ └── jvms.jpg │ ├── fonts │ ├── element-icons.535877f.woff │ └── element-icons.732389d.ttf │ ├── img │ ├── bg2.ef8085e.png │ ├── cc-logo.3653e37.png │ ├── logo-color.5500ec5.png │ └── mmall.4971f42.png │ └── js │ ├── 0.c178f427b3d08777c70f.js │ ├── 1.6f63d09ab120b212c44d.js │ ├── 2.8df64f24adb63dcd7dcd.js │ ├── 3.de05a3e78470a7ab50f1.js │ ├── 4.ebe3ae2a78397bdf1010.js │ ├── 5.c79741f8718eb55113ff.js │ ├── 6.e2f43265608e8bcfeec1.js │ ├── 7.7f99ce3702c32ec932ca.js │ ├── 8.c0df9daed0421a7c48c4.js │ ├── 9.1fd42476fd68c9cb70b0.js │ ├── app.b692bd72e6d421b5e096.js │ ├── manifest.c1c199c8b8d75f95329a.js │ └── vendor.c2f13a2146485051ae24.js ├── mmall-platform-registry ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── kay │ │ └── mmall │ │ └── RegistryApplication.java │ └── resources │ └── bootstrap.yml └── settings.gradle /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - feature/microservices_springcloud 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Cache SonarCloud packages 21 | uses: actions/cache@v1 22 | with: 23 | path: ~/.sonar/cache 24 | key: ${{ runner.os }}-sonar 25 | restore-keys: ${{ runner.os }}-sonar 26 | - name: Cache Gradle packages 27 | uses: actions/cache@v1 28 | with: 29 | path: ~/.gradle/caches 30 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 31 | restore-keys: ${{ runner.os }}-gradle 32 | - name: Build and analyze 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GB_TOKEN }} # Needed to get PR information, if any 35 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 36 | run: ./gradlew build sonarqube --info 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MMall 2 | 3 | [](https://sonarcloud.io/summary/new_code?id=LiuKay_mmall-java) 4 | [](https://sonarcloud.io/summary/new_code?id=LiuKay_mmall-java) 5 | 6 | 7 | A simple project to learn different architectures. 8 | 9 | ## What - 这是什么 10 | 11 | Mmall 是一个十分简化的商城项目,仅包含了用户、支付、库存管理等能支撑一个购物流程的业务功能,同时也包括了一些非业务功能, 12 | 包括登录、身份认证、鉴权等。通过一些简化,从而来更好的学习不同的架构风格是什么样的。从单体服务风格,到微服务架构,再到 13 | 云原生,不同的架构为了架构本身的问题而引入了一些新的组件。 14 | 15 | > Based on [https://github.com/fenixsoft/monolithic_arch_springboot](https://github.com/fenixsoft/monolithic_arch_springboot) and made some improvements. 16 | > 17 | > 本项目基于周志明老师的[凤凰架构](https://icyfenix.cn/introduction/about-the-fenix-project.html)中的示例项目:[单体架构](https://github.com/fenixsoft/monolithic_arch_springboot). 在此基础上做一些改进和修改。 18 | 19 | 20 | ## Current Version - 当前分支版本: 21 | 22 | Microservices SpringCloud - 微服务 SpringCloud 版: [microservices_springcloud]([LiuKay/mmall-java at microservices_springcloud (github.com)](https://github.com/LiuKay/mmall-java/tree/microservices_springcloud)) 23 | 24 | | service | port | comment | 25 | | ---------------------------- | ---- | -------------------------------------------------------- | 26 | | mmall-domain-security | 8301 | security service, OAuth2, JWT | 27 | | mmall-domain-account | 8401 | account service | 28 | | mmall-domain-warehouse | 8501 | product, stockpile service | 29 | | mmall-domain-payment | 8601 | payment, wallet service | 30 | | mmall-domain-registry | 8761 | services registry center | 31 | | mmall-domain-gateway | 8080 | API Gateway | 32 | | mmall-platform-configuration | 8888 | configurations | 33 | | mmall-lib-infrastructure | NA | infrastructure library, domain, dto, utils, lock service | 34 | | | | | 35 | 36 | 37 | ## Technology - 技术选型 38 | 39 | - SpringBoot 40 | - Spring Cache + Redis 41 | - Redisson as distributed lock 42 | - Spring Data JPA 43 | - Spring Security 44 | - Spring Security OAuth 2.3 45 | - Spring Security JWT 46 | - Jackson 47 | - Bean Validation 2.0 (Hibernate Validator 6) 48 | - Netflix Zuul 49 | - Netflix Eureka 50 | - Netflix Feign 51 | - Spring Config 52 | 53 | ## Get Started 54 | 55 | ### Local Run - 本地运行 56 | 57 | 依赖的测试基础设施环境使用 Docker Compose 打包(见 docker-compose.yml),MySQL, Redis 等。 58 | 59 | 本地演示会将所有service 打包到 Docker 运行,详情见 `docker-compose.dev.yml` 60 | 61 | ```shell 62 | # 启动 docker 之后可以使用该命令启动演示 63 | ./deploy_to_docker.sh 64 | 65 | # 或者 66 | ./gradlew clean 67 | ./gradlew assemble 68 | docker-compose -f ./docker-compose.dev.yml up -d 69 | ``` 70 | 71 | ### Debug - 调式模式 72 | 73 | 调式模式只在 Docker 环境中启动需要的基础设施,如 Redis, MySQL 等,业务服务可以在 IDEA 中分别启动,或使用 Gradle 命令分别启动,按照先启动 registery,configuration 再启动其他。 74 | 75 | ```shell 76 | # 1.setup infrastructure 77 | docker-compose -f ./docker-compose.debug.yml up -d 78 | 79 | # 2.setup services 80 | ./gradlew :mmall-platform-registry:bootRun 81 | ./gradlew :mmall-platform-configuration:bootRun 82 | ./gradlew :mmall-platform-gateway:bootRun 83 | ./gradlew :mmall-domain-security:bootRun 84 | ./gradlew :mmall-domain-account:bootRun 85 | ./gradlew :mmall-domain-payment:bootRun 86 | ./gradlew :mmall-domain-warehouse:bootRun 87 | ``` 88 | 89 | 90 | 91 | 进入主页 [http://localhost:8080/](http://localhost:8080/) 默认账号 kaybee, 密码 123456 92 | 93 |  94 | 95 | ----- 96 | 97 | ### Develop Plan - 开发计划 98 | 99 | - 单体版本使用 SpringBoot (已完成),分支: [feature/monolithic_springboot](https://github.com/LiuKay/mmall-java/tree/feature/monolithic_springboot) 100 | - 微服务版本使用 Spring Cloud 体系 (已完成),分支:[feature/microservices_springcloud](https://github.com/LiuKay/mmall-java/tree/feature/microservices_springcloud) 101 | - K8s 版本 (开发中) 102 | 103 | ## Frontend Project - 前端项目 104 | 105 | [https://github.com/LiuKay/mmall-frontend](https://github.com/LiuKay/mmall-frontend) 106 | 107 | ## Other Versions - 其他版本(分支) 108 | 109 | - v1.0 110 | 111 | 单服务器 + FTP文件服务器, 112 | 113 | 主要技术:SSM/Guava/Jackson/Joda/注解 114 | 115 | - v2.0 116 | 117 | Tomcat集群+Nginx负载均衡+Redis分布式, 118 | 119 | 在V1.0基础上进行迭代重构,主要技术Redis 、Spring Schedule、Tomcat集群、Nginx负载均衡 120 | 121 | - v3.0_springboot_Deprecated (已废弃) 122 | 123 | 重构了登录鉴权的部分 124 | 125 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '2.2.5.RELEASE' 4 | id 'io.spring.dependency-management' version '1.0.10.RELEASE' 5 | id "org.sonarqube" version "3.4.0.2513" 6 | } 7 | 8 | bootJar { 9 | mainClassName = "mmall-springcloud" 10 | } 11 | 12 | subprojects { 13 | apply plugin: 'java' 14 | apply plugin: 'idea' 15 | apply plugin: 'io.spring.dependency-management' 16 | 17 | group = 'com.github.kay' 18 | version = '0.0.1-SNAPSHOT' 19 | 20 | dependencyManagement { 21 | imports { 22 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR8" 23 | mavenBom "org.springframework.boot:spring-boot-dependencies:2.2.5.RELEASE" 24 | } 25 | } 26 | 27 | compileJava { 28 | sourceCompatibility = '11' 29 | targetCompatibility = '11' 30 | } 31 | 32 | dependencies { 33 | annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" 34 | 35 | compileOnly 'org.projectlombok:lombok:1.18.24' 36 | annotationProcessor 'org.projectlombok:lombok:1.18.24' 37 | 38 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' 39 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' 40 | } 41 | } 42 | 43 | sonarqube { 44 | properties { 45 | property "sonar.projectKey", "LiuKay_mmall-java" 46 | property "sonar.organization", "liukay" 47 | property "sonar.host.url", "https://sonarcloud.io" 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /deploy_to_docker.sh: -------------------------------------------------------------------------------- 1 | # /bin/sh 2 | 3 | ./gradlew clean 4 | ./gradlew assemble 5 | 6 | #./gradlew :mmall-domain-account:bootJar 7 | #./gradlew :mmall-domain-payment:bootJar 8 | #./gradlew :mmall-domain-warehouse:bootJar 9 | #./gradlew :mmall-domain-security:bootJar 10 | #./gradlew :mmall-platform-configuration:bootJar 11 | #./gradlew :mmall-platform-gateway:bootJar 12 | #./gradlew :mmall-platform-registry:bootJar 13 | 14 | docker-compose -f ./docker-compose.dev.yml up -d 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docker-compose.debug.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | mysql: 5 | image: mysql:5.7.38 6 | ports: 7 | - 3306:3306 8 | environment: 9 | - MYSQL_ROOT_PASSWORD=root1234 10 | - MYSQL_DATABASE=mmall 11 | - MYSQL_USER=mmall 12 | - MYSQL_PASSWORD=mmall 13 | command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci 14 | 15 | redis: 16 | image: redis:latest 17 | ports: 18 | - 6379:6379 19 | command: redis-server --notify-keyspace-events Ex -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | mysql: 5 | image: mysql:5.7.38 6 | ports: 7 | - 3306:3306 8 | environment: 9 | - MYSQL_ROOT_PASSWORD=root1234 10 | - MYSQL_DATABASE=mmall 11 | - MYSQL_USER=mmall 12 | - MYSQL_PASSWORD=mmall 13 | command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci 14 | healthcheck: 15 | test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ] 16 | timeout: 20s 17 | retries: 10 18 | 19 | redis: 20 | image: redis:latest 21 | ports: 22 | - 6379:6379 23 | command: redis-server --notify-keyspace-events Ex 24 | 25 | mmall-configuration: 26 | build: mmall-platform-configuration 27 | restart: always 28 | depends_on: 29 | mysql: 30 | condition: service_healthy 31 | ports: 32 | - 8888:8888 33 | 34 | mmall-registry: 35 | build: mmall-platform-registry 36 | environment: 37 | CONFIG_HOST: mmall-configuration 38 | restart: always 39 | depends_on: 40 | mmall-configuration: 41 | condition: service_healthy 42 | ports: 43 | - 8761:8761 44 | 45 | mmall-gateway: 46 | build: mmall-platform-gateway 47 | depends_on: 48 | mmall-configuration: 49 | condition: service_healthy 50 | environment: 51 | CONFIG_HOST: mmall-configuration 52 | REGISTRY_HOST: mmall-registry 53 | restart: always 54 | ports: 55 | - 8080:8080 56 | 57 | mmall-security: 58 | build: mmall-domain-security 59 | depends_on: 60 | mmall-configuration: 61 | condition: service_healthy 62 | environment: 63 | CONFIG_HOST: mmall-configuration 64 | REGISTRY_HOST: mmall-registry 65 | restart: always 66 | ports: 67 | - 8301:8301 68 | 69 | mmall-account: 70 | build: mmall-domain-account 71 | depends_on: 72 | mmall-configuration: 73 | condition: service_healthy 74 | environment: 75 | CONFIG_HOST: mmall-configuration 76 | REGISTRY_HOST: mmall-registry 77 | AUTH_HOST: mmall-security 78 | MYSQL_URL: jdbc:mysql://mysql/mmall?useUnicode=true&characterEncoding=utf-8 79 | REDIS_HOST: redis 80 | restart: always 81 | 82 | mmall-warehouse: 83 | build: mmall-domain-warehouse 84 | depends_on: 85 | mmall-configuration: 86 | condition: service_healthy 87 | environment: 88 | CONFIG_HOST: mmall-configuration 89 | REGISTRY_HOST: mmall-registry 90 | AUTH_HOST: mmall-security 91 | REDIS_HOST: redis 92 | MYSQL_URL: jdbc:mysql://mysql/mmall?useUnicode=true&characterEncoding=utf-8 93 | restart: always 94 | ports: 95 | - 8501:8501 96 | 97 | mmall-payment: 98 | build: mmall-domain-payment 99 | depends_on: 100 | mmall-configuration: 101 | condition: service_healthy 102 | environment: 103 | CONFIG_HOST: mmall-configuration 104 | REGISTRY_HOST: mmall-registry 105 | AUTH_HOST: mmall-security 106 | REDIS_HOST: redis 107 | MYSQL_URL: jdbc:mysql://mysql/mmall?useUnicode=true&characterEncoding=utf-8 108 | restart: always 109 | ports: 110 | - 8601:8601 111 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuKay/mmall-java/681436fe8768399ad07ebece2993cb996442bc59/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /img/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiuKay/mmall-java/681436fe8768399ad07ebece2993cb996442bc59/img/home.png -------------------------------------------------------------------------------- /mmall-domain-account/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | 3 | MAINTAINER kaybee 4 | 5 | ENV SPRING_OUTPUT_ANSI_ENABLE=ALWAYS \ 6 | JAVA_OPT="" \ 7 | PORT=8401 \ 8 | CONFIG_PORT=8888 \ 9 | AUTH_PORT=8301 \ 10 | PROFILES="default" 11 | 12 | ADD /build/libs/*.jar /mmall-account.jar 13 | 14 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPT -jar /mmall-account.jar --spring.profiles.active=$PROFILES"] 15 | 16 | EXPOSE $PORT 17 | -------------------------------------------------------------------------------- /mmall-domain-account/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | configurations { 8 | implementation { 9 | exclude group: 'com.sun.jersey', module: 'jersey-client' 10 | exclude group: 'com.sun.jersey', module: 'jersey-core' 11 | exclude group: 'com.sun.jersey.contribs', module: 'jersey-apache-client4' 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation project(':mmall-lib-infrastructure') 17 | 18 | implementation 'org.springframework.boot:spring-boot-starter' 19 | implementation 'org.springframework.boot:spring-boot-starter-web' 20 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 21 | implementation 'org.springframework.cloud:spring-cloud-starter-security' 22 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' 23 | } 24 | 25 | -------------------------------------------------------------------------------- /mmall-domain-account/src/main/java/com/github/kay/mmall/account/AccountApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.kay.mmall.account; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cache.annotation.EnableCaching; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | 8 | @EnableCaching 9 | @EnableDiscoveryClient 10 | @SpringBootApplication(scanBasePackages = {"com.github.kay.mmall"}) 11 | public class AccountApplication { 12 | public static void main(String[] args) { 13 | SpringApplication.run(AccountApplication.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /mmall-domain-account/src/main/java/com/github/kay/mmall/account/application/AccountApplicationService.java: -------------------------------------------------------------------------------- 1 | package com.github.kay.mmall.account.application; 2 | 3 | import com.github.kay.mmall.domain.account.Account; 4 | import com.github.kay.mmall.account.domain.AccountRepository; 5 | import org.springframework.security.crypto.password.PasswordEncoder; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | @Service 10 | @Transactional 11 | public class AccountApplicationService { 12 | 13 | private final AccountRepository repository; 14 | private final PasswordEncoder encoder; 15 | 16 | public AccountApplicationService(AccountRepository repository, 17 | PasswordEncoder encoder) { 18 | this.repository = repository; 19 | this.encoder = encoder; 20 | } 21 | 22 | public void createAccount(Account account) { 23 | account.setPassword(encoder.encode(account.getPassword())); 24 | repository.save(account); 25 | } 26 | 27 | public Account findAccountByUsername(String username) { 28 | return repository.findByUsername(username); 29 | } 30 | 31 | public void updateAccount(Account account) { 32 | repository.save(account); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /mmall-domain-account/src/main/java/com/github/kay/mmall/account/application/AddressApplicationService.java: -------------------------------------------------------------------------------- 1 | package com.github.kay.mmall.account.application; 2 | 3 | import com.github.kay.mmall.domain.account.Address; 4 | import com.github.kay.mmall.account.domain.AddressRepository; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.util.Collection; 8 | 9 | @Service 10 | public class AddressApplicationService { 11 | 12 | private final AddressRepository addressRepository; 13 | 14 | public AddressApplicationService(AddressRepository addressRepository) { 15 | this.addressRepository = addressRepository; 16 | } 17 | 18 | public Collection
listAddresses(Integer userId) { 19 | return addressRepository.findAddressesByUserId(userId); 20 | } 21 | 22 | public void createAddress(Address address) { 23 | addressRepository.save(address); 24 | } 25 | 26 | public void updateAddress(Address address) { 27 | addressRepository.save(address); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /mmall-domain-account/src/main/java/com/github/kay/mmall/account/controller/AccountController.java: -------------------------------------------------------------------------------- 1 | package com.github.kay.mmall.account.controller; 2 | 3 | import com.github.kay.mmall.account.application.AccountApplicationService; 4 | import com.github.kay.mmall.account.domain.validation.AuthenticatedAccount; 5 | import com.github.kay.mmall.account.domain.validation.NotConflictAccount; 6 | import com.github.kay.mmall.account.domain.validation.UniqueAccount; 7 | import com.github.kay.mmall.domain.account.Account; 8 | import com.github.kay.mmall.infrasucture.common.CodedMessage; 9 | import com.github.kay.mmall.infrasucture.common.CommonResponse; 10 | import com.github.kay.mmall.infrasucture.common.ResourceNotFoundException; 11 | 12 | import org.springframework.cache.annotation.CacheConfig; 13 | import org.springframework.cache.annotation.CacheEvict; 14 | import org.springframework.cache.annotation.Cacheable; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.security.access.prepost.PreAuthorize; 17 | import org.springframework.validation.annotation.Validated; 18 | import org.springframework.web.bind.annotation.GetMapping; 19 | import org.springframework.web.bind.annotation.PathVariable; 20 | import org.springframework.web.bind.annotation.PostMapping; 21 | import org.springframework.web.bind.annotation.PutMapping; 22 | import org.springframework.web.bind.annotation.RequestBody; 23 | import org.springframework.web.bind.annotation.RequestMapping; 24 | import org.springframework.web.bind.annotation.RestController; 25 | 26 | import java.util.Optional; 27 | 28 | @Validated 29 | @CacheConfig(cacheNames = "resource.account") 30 | @RestController 31 | @RequestMapping("/restful/accounts") 32 | public class AccountController { 33 | 34 | private final AccountApplicationService service; 35 | 36 | public AccountController(AccountApplicationService service) { 37 | this.service = service; 38 | } 39 | 40 | //Note 此方法的返回包含了 password,需要将 password 和 用户的其他信息分开存储,需要的时候各取所需 41 | @GetMapping("/{username}") 42 | @Cacheable(key = "#username") 43 | @PreAuthorize("#oauth2.hasAnyScope('SERVICE','BROWSER')") 44 | public Account getUser(@PathVariable String username) { 45 | return Optional.ofNullable(service.findAccountByUsername(username)) 46 | .orElseThrow( 47 | ResourceNotFoundException.supplier(String.format("Not found for username:%s", username))); 48 | } 49 | 50 | @PostMapping 51 | @CacheEvict(key = "#user.username") 52 | public ResponseEntity38 | * 一个认证服务管理器里面包含着多个可以从事不同认证类型的认证提供者(Provider) 39 | * 认证服务由认证服务器{@link AuthenticationServerConfiguration}定义并提供注入源 40 | */ 41 | @Autowired 42 | private AuthenticationManager authenticationManager; 43 | 44 | /** 45 | * 用户信息服务 46 | */ 47 | @Autowired 48 | private AuthenticAccountDetailsService accountService; 49 | 50 | @Override 51 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 52 | clients.withClientDetails(clientService); 53 | } 54 | 55 | /** 56 | * 配置授权的服务Endpoint 57 | *
58 | * Spring Security OAuth2会根据配置的认证服务、用户详情服务、令牌服务自动生成以下端点: 59 | * /oauth/authorize:授权端点 60 | * /oauth/token:令牌端点 61 | * /oauth/confirm_access:用户确认授权提交端点 62 | * /oauth/error:授权服务错误信息端点 63 | * /oauth/check_token:用于资源服务访问的令牌解析端点 64 | * /oauth/token_key:提供公有密匙的端点,如果JWT采用的是非对称加密加密算法,则资源服务其在鉴权时就需要这个公钥来解码 65 | * 如有必要,这些端点可以使用pathMapping()方法来修改它们的位置,使用prefix()方法来设置路径前缀 66 | */ 67 | @Override 68 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 69 | endpoints.authenticationManager(authenticationManager) 70 | .userDetailsService(accountService) 71 | .tokenServices(tokenService) 72 | .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); 73 | } 74 | 75 | /** 76 | * 配置OAuth2发布出来的Endpoint本身的安全约束 77 | *
78 | * 这些端点的默认访问规则原本是: 79 | * 1. 端点开启了HTTP Basic Authentication,通过allowFormAuthenticationForClients()关闭,即允许通过表单来验证 80 | * 2. 端点的访问均为denyAll(),可以在这里通过SpringEL表达式来改变为permitAll() 81 | */ 82 | @Override 83 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 84 | security.allowFormAuthenticationForClients() 85 | .tokenKeyAccess("permitAll()") 86 | .checkTokenAccess("permitAll()"); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /mmall-domain-security/src/main/java/com/github/kay/mmall/security/configuration/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.kay.mmall.security.configuration; 2 | 3 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 4 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 8 | 9 | @Override 10 | protected void configure(HttpSecurity http) throws Exception { 11 | http.headers() 12 | .cacheControl() 13 | .disable(); 14 | } 15 | 16 | @Override 17 | public void configure(WebSecurity web) throws Exception { 18 | web.ignoring() 19 | .antMatchers("/static/**"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mmall-domain-security/src/main/java/com/github/kay/mmall/security/provider/PreAuthenticatedAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.github.kay.mmall.security.provider; 2 | 3 | import com.github.kay.mmall.domain.security.AuthenticAccount; 4 | import org.springframework.security.authentication.AuthenticationProvider; 5 | import org.springframework.security.authentication.DisabledException; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.AuthenticationException; 9 | import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; 10 | import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * 预验证身份认证器 15 | *
16 | * 预验证是指身份已经在其他地方(第三方)确认过 17 | * 预验证器的目的是将第三方身份管理系统集成到具有Spring安全性的Spring应用程序中,在本项目中,用于JWT令牌过期后重刷新时的验证 18 | * 此时只要检查用户是否有停用、锁定、密码过期、账号过期等问题,如果没有,可根据JWT令牌的刷新过期期限,重新给客户端发放访问令牌 19 | */ 20 | 21 | @Component 22 | public class PreAuthenticatedAuthenticationProvider implements AuthenticationProvider { 23 | 24 | @Override 25 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 26 | if (authentication.getPrincipal() instanceof UsernamePasswordAuthenticationToken) { 27 | UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication.getPrincipal(); 28 | AuthenticAccount account = (AuthenticAccount) token.getPrincipal(); 29 | 30 | if (account.isEnabled() && account.isCredentialsNonExpired() && account.isAccountNonExpired() && account.isAccountNonLocked()) { 31 | return new PreAuthenticatedAuthenticationToken(account, "", account.getAuthorities()); 32 | }else { 33 | throw new DisabledException("Account status is illegal."); 34 | } 35 | }else { 36 | throw new PreAuthenticatedCredentialsNotFoundException("Pre-Authentication failed, token is invalid."); 37 | } 38 | } 39 | 40 | @Override 41 | public boolean supports(Class> aClass) { 42 | return aClass.equals(PreAuthenticatedAuthenticationToken.class); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mmall-domain-security/src/main/java/com/github/kay/mmall/security/provider/RSA256JWTAccessToken.java: -------------------------------------------------------------------------------- 1 | package com.github.kay.mmall.security.provider; 2 | 3 | import com.github.kay.mmall.infrasucture.security.JWTAccessToken; 4 | 5 | import org.springframework.context.annotation.Primary; 6 | import org.springframework.core.io.ClassPathResource; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.security.jwt.JwtHelper; 9 | import org.springframework.security.jwt.crypto.sign.Signer; 10 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 11 | import org.springframework.security.oauth2.common.util.JsonParser; 12 | import org.springframework.security.oauth2.common.util.JsonParserFactory; 13 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 14 | import org.springframework.security.rsa.crypto.KeyStoreKeyFactory; 15 | import org.springframework.stereotype.Service; 16 | import org.springframework.util.ReflectionUtils; 17 | 18 | import java.lang.reflect.Field; 19 | import java.util.Collections; 20 | import java.util.Map; 21 | 22 | /** 23 | * 使用RSA SHA256私钥加密的JWT令牌 24 | *
25 | * 为了便于对比,
26 | *
27 | * 生成jks私钥公钥等
28 | * keytool -genkeypair -alias mmall-rsa -keyalg RSA -keypass 123456 -keystore rsa.jks -storepass 123456 -validity 36500
29 | * keytool -list -rfc --keystore rsa.jks | openssl x509 -inform pem -pubkey > pubkey.txt
30 | *
31 | **/
32 | @Service
33 | @Primary
34 | public class RSA256JWTAccessToken extends JWTAccessToken {
35 |
36 | private final JsonParser objectMapper = JsonParserFactory.create();
37 |
38 | RSA256JWTAccessToken(UserDetailsService userDetailsService) {
39 | super(userDetailsService);
40 | KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("rsa.jks"), "123456".toCharArray());
41 | setKeyPair(keyStoreKeyFactory.getKeyPair("mmall-rsa"));
42 | }
43 |
44 | /**
45 | * 增强令牌Header
46 | * 使用JWKS验证令牌时,Header中需要有kid(Key ID),设置Header的方法在Spring的默认实现中没有开放出来,这里添加个默认处理
47 | */
48 | @Override
49 | protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
50 | Field signerField = ReflectionUtils.findField(this.getClass(), "signer");
51 | signerField.setAccessible(true);
52 | Signer signer = (Signer) ReflectionUtils.getField(signerField, this);
53 |
54 | String content;
55 | try {
56 | content = this.objectMapper.formatMap(getAccessTokenConverter().convertAccessToken(accessToken, authentication));
57 | } catch (Exception ex) {
58 | throw new IllegalStateException("Cannot convert access token to JSON", ex);
59 | }
60 |
61 | Map 这是一部从工作原理和工程实践两个维度深入剖析JVM的著作,是计算机领域公认的经典,繁体版在台湾也颇受欢迎。 自2011年上市以来,前两个版本累计印刷36次,销量超过30万册,两家主要网络书店的评论近90000条,内容上近乎零差评,是原创计算机图书领域不可逾越的丰碑,第3版在第2版的基础上做了重大修订,内容更丰富、实战性更强:根据新版JDK对内容进行了全方位的修订和升级,围绕新技术和生产实践新增逾10万字,包含近50%的全新内容,并对第2版中含糊、瑕疵和错误内容进行了修正。 全书一共13章,分为五大部分: 第一部分(第1章)走近Java 系统介绍了Java的技术体系、发展历程、虚拟机家族,以及动手编译JDK,了解这部分内容能对学习JVM提供良好的指引。 第二部分(第2~5章)自动内存管理 详细讲解了Java的内存区域与内存溢出、垃圾收集器与内存分配策略、虚拟机性能监控与故障排除等与自动内存管理相关的内容,以及10余个经典的性能优化案例和优化方法; 第三部分(第6~9章)虚拟机执行子系统 深入分析了虚拟机执行子系统,包括类文件结构、虚拟机类加载机制、虚拟机字节码执行引擎,以及多个类加载及其执行子系统的实战案例; 第四部分(第10~11章)程序编译与代码优化 详细讲解了程序的前、后端编译与优化,包括前端的易用性优化措施,如泛型、主动装箱拆箱、条件编译等的内容的深入分析;以及后端的性能优化措施,如虚拟机的热点探测方法、HotSpot 的即时编译器、提前编译器,以及各种常见的编译期优化技术; 第五部分(第12~13章)高效并发 主要讲解了Java实现高并发的原理,包括Java的内存模型、线程与协程,以及线程安全和锁优化。 全书以实战为导向,通过大量与实际生产环境相结合的案例分析和展示了解决各种Java技术难题的方案和技巧。 测试描述 测试描述 测试描述 测试描述 测试描述
19 | * JWT令牌的结构为三部分组成:[令牌头(Header)].[负载信息(Payload)].[签名(Signature)]
20 | * 令牌头:定义了令牌的元数据,如令牌采用的签名算法,默认为HMAC SHA256算法
21 | * 负载信息:由签发者自定义的数据,一般会包括过期时间(Expire)、授权范围(Authority)、令牌ID编号(JTI)等
22 | * 签名:签名是使用私钥和头部指定的算法,前两部分进行的数字签名,防止数据被篡改。
23 | * 以上,令牌头和负载均为JSON结构,进行Base64URLEncode之后进行签名,然后用“.”连接,构成令牌报文
24 | *
25 | * Spring Security OAuth2的{@link JwtAccessTokenConverter}提供了令牌的基础结构(令牌头、部分负载,如过期时间、JTI)的转换实现
26 | * 继承此类,在加入自己定义的负载信息即可使用。一般来说负载中至少要告知服务端当前用户是谁,但又不应存放过多信息导致HTTP Header过大,尤其不应存放敏感信息。
27 | *
28 | * @author icyfenix@gmail.com
29 | * @date 2020/3/9 9:46
30 | */
31 | public class JWTAccessToken extends JwtAccessTokenConverter {
32 |
33 | public JWTAccessToken(UserDetailsService userDetailsService) {
34 | // 设置从资源请求中带上来的JWT令牌转换回安全上下文中的用户信息的查询服务
35 | // 如果不设置该服务,则从JWT令牌获得的Principal就只有一个用户名(令牌中确实就只存了用户名)
36 | // 将用户用户信息查询服务提供给默认的令牌转换器,使得转换令牌时自动根据用户名还原出完整的用户对象
37 | // 这方便了后面编码(可以在直接获得登陆用户信息),但也稳定地为每次请求增加了一次(从数据库/缓存)查询,自行取舍
38 | DefaultUserAuthenticationConverter converter = new DefaultUserAuthenticationConverter();
39 | converter.setUserDetailsService(userDetailsService);
40 | ((DefaultAccessTokenConverter)getAccessTokenConverter()).setUserTokenConverter(converter);
41 | }
42 |
43 | /**
44 | * 增强令牌
45 | * 增强主要就是在令牌的负载中加入额外的信息
46 | */
47 | @Override
48 | public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
49 | Authentication user = authentication.getUserAuthentication();
50 | if (user != null) {
51 | String[] authorities = user.getAuthorities().stream().map(GrantedAuthority::getAuthority).toArray(String[]::new);
52 | Map
14 | * 在此服务中提供了令牌如何存储、携带哪些信息、如何签名、持续多长时间等相关内容的定义
15 | * 令牌服务应当会被授权服务器注册验证Endpoint时候调用到
16 | *
17 | * @author icyfenix@gmail.com
18 | * @date 2020/3/8 11:07
19 | **/
20 | @Component
21 | public class JWTAccessTokenService extends DefaultTokenServices {
22 | /**
23 | * 构建JWT令牌,并进行默认的配置
24 | */
25 | public JWTAccessTokenService(JWTAccessToken token,
26 | OAuthClientDetailsService clientService,
27 | Optional
21 | * OAuth2支持四种授权模式,这里仅定义了密码模式(Resource Owner Password Credentials Grant)一种
22 | * OAuth2作为开放的(面向不同服务提供商)授权协议,要求用户提供明文用户名、密码的这种“密码模式”并不常用
23 | * 而这里可以采用是因为前端(BookStore FrontEnd)与后端服务是属于同一个服务提供者的,实质上不存在密码会不会被第三方保存的敏感问题.
24 | *
25 | * 如果永远只考虑单体架构、单一服务提供者,则并无引入OAuth的必要,Spring Security的表单认证就能很良好、便捷地解决认证和授权的问题
26 | * 这里使用密码模式来解决,是为了下一阶段演示微服务化后,服务之间鉴权作准备,以便后续扩展以及对比。
27 | *
28 | * @author icyfenix@gmail.com
29 | * @date 2020/3/7 19:45
30 | **/
31 | @Component
32 | public class OAuthClientDetailsService implements ClientDetailsService {
33 |
34 | /**
35 | * 客户端模型
36 | */
37 | private static class Client {
38 | /**
39 | * 客户端ID
40 | */
41 | String clientId;
42 |
43 | /**
44 | * 客户端密钥
45 | * 在OAuth2协议中,ID是可以公开的,密钥应当保密,密钥用以证明当前申请授权的客户端是未被冒充的
46 | */
47 | String clientSecret;
48 |
49 | /**
50 | * 授权类型
51 | * 前端API使用密码授权模式,微服务使用客户端授权模式
52 | */
53 | String[] grantTypes;
54 |
55 | /**
56 | * 授权范围
57 | */
58 | String[] scopes;
59 |
60 | Client(String clientId, String clientSecret, String[] grantTypes, String[] scopes) {
61 | this.clientId = clientId;
62 | this.clientSecret = clientSecret;
63 | this.grantTypes = grantTypes;
64 | this.scopes = scopes;
65 | }
66 | }
67 |
68 | /**
69 | * 客户端列表
70 | *
71 | * 此场景中微服务一种有JavaScript前端、Account微服务、Warehouse微服务、Payment微服务四种客户端
72 | * 如果正式使用,这部分信息应该做成可以配置的,以便快速增加微服务的类型。clientSecret也不应该出现在源码中,应由外部配置传入
73 | */
74 | private static final List
23 | * 配置资源服务访问权限,主流有两种方式:
24 | * 一是在这里通过{@link HttpSecurity}的antMatchers
方法集中配置
25 | * 二是启用全局方法级安全支持{@link EnableGlobalMethodSecurity} 在各个资源的访问方法前,通过注解来逐个配置,使用的注解包括有:
26 | * JSR 250标准注解{@link RolesAllowed},可完整替代Spring的{@link Secured}功能
27 | * 以及可以使用EL表达式的Spring注解{@link PreAuthorize}、{@link PostAuthorize}
28 | *
29 | * @author icyfenix@gmail.com
30 | * @date 2020/3/7 19:43
31 | **/
32 | @Configuration
33 | @EnableResourceServer
34 | public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
35 |
36 | @Autowired
37 | private JWTAccessTokenService tokenService;
38 |
39 | /**
40 | * 配置HTTP访问相关的安全选项
41 | */
42 | @Override
43 | public void configure(HttpSecurity http) throws Exception {
44 | // 基于JWT来绑定用户状态,所以服务端可以是无状态的
45 | http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
46 | // 关闭CSRF(Cross Site Request Forgery)跨站请求伪造的防御
47 | // 因为需要状态存储CSRF Token才能开启该功能
48 | http.csrf().disable();
49 | // 关闭HTTP Header中的X-Frame-Options选项,允许页面在frame标签中打开
50 | http.headers().frameOptions().disable();
51 | // 设置服务的安全规则
52 | http.authorizeRequests().antMatchers("/oauth/**").permitAll();
53 | }
54 |
55 | @Override
56 | public void configure(ResourceServerSecurityConfigurer resources) {
57 | resources.tokenServices(tokenService);
58 | }
59 |
60 | @Bean
61 | @ConfigurationProperties(prefix = "security.oauth2.client")
62 | public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
63 | return new ClientCredentialsResourceDetails();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:12-alpine
2 |
3 | MAINTAINER kaybee
4 |
5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
6 | JAVA_OPTS="" \
7 | PORT=8888 \
8 | PROFILES="native"
9 |
10 | ADD /build/libs/*.jar /mmall-config.jar
11 |
12 | RUN apk update && apk add curl && rm -rf /var/cache/apk/*
13 |
14 | HEALTHCHECK --interval=5s --timeout=30s CMD curl -f http://localhost:$PORT/actuator/health || exit 1
15 |
16 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPT -jar /mmall-config.jar --spring.profiles.active=$PROFILES"]
17 |
18 | EXPOSE $PORT
--------------------------------------------------------------------------------
/mmall-platform-configuration/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'org.springframework.boot'
4 | id 'io.spring.dependency-management'
5 | }
6 |
7 |
8 | dependencies {
9 | implementation 'org.springframework.cloud:spring-cloud-config-server'
10 | implementation 'org.springframework.boot:spring-boot-starter-actuator'
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/java/com/github/kay/mmall/ConfigurationApplication.java:
--------------------------------------------------------------------------------
1 | package com.github.kay.mmall;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.config.server.EnableConfigServer;
6 |
7 | @EnableConfigServer
8 | @SpringBootApplication
9 | public class ConfigurationApplication {
10 | public static void main(String[] args) {
11 | SpringApplication.run(ConfigurationApplication.class, args);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | cloud:
3 | config:
4 | server:
5 | native:
6 | search-locations: classpath:/configurations
7 | profiles:
8 | active: native
9 | security:
10 | user:
11 | password: ${CONFIG_PASS:dev}
12 |
13 | management:
14 | endpoints:
15 | web:
16 | exposure:
17 | include: "*"
18 |
19 | server:
20 | port: ${PORT:8888}
21 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/resources/configurations/account.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${REGISTRY_HOST:localhost}:${REGISTRY_PORT:8761}/eureka/
5 |
6 | spring:
7 | cache:
8 | type: redis
9 | redis:
10 | cache-null-values: false
11 | time-to-live: PT5M
12 | datasource:
13 | schema: "classpath:db/schema.sql"
14 | data: "classpath:db/data.sql"
15 | sql-script-encoding: UTF-8
16 | url: ${MYSQL_URL:jdbc:mysql://localhost/mmall?useUnicode=true&characterEncoding=utf-8}
17 | username: "root"
18 | password: "root1234"
19 | initialization-mode: always
20 | jpa:
21 | show-sql: true
22 | hibernate:
23 | ddl-auto: none
24 | open-in-view: true
25 | generate-ddl: false
26 | database: mysql
27 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
28 | resources:
29 | chain:
30 | compressed: true
31 | cache: true
32 | cache:
33 | period: 86400
34 | redis:
35 | host: ${REDIS_HOST:localhost}
36 | port: ${REDIS_PORT:6379}
37 |
38 | logging:
39 | pattern:
40 | console: "%clr(%d{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:%5p}) %clr(-){faint} %clr([%t]){faint} %clr(%-40logger{39}){cyan}[%line]%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}"
41 | level:
42 | root: INFO
43 | com.github.kay: DEBUG
44 |
45 | security:
46 | oauth2:
47 | client:
48 | # OAuth的ClientID和ClientSecret是写在OAuthClientDetailsService中的
49 | # 实际生产中要考虑好如何获取验证服务器的Endpoint、动态增加微服务客户端、如何分发客户端密钥等问题,而在演示工程中并不关注这些
50 | clientId: account
51 | clientSecret: account_secret
52 | accessTokenUri: http://${AUTH_HOST:localhost}:${AUTH_PORT:8301}/oauth/token
53 | grant-type: client_credentials
54 | scope: SERVICE
55 | resource:
56 | userInfoUri: BUGFIX
57 |
58 | server:
59 | port: ${PORT:8401}
60 |
61 | mmall:
62 | redisson-config: "redisson-config.yml"
63 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/resources/configurations/gateway.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${REGISTRY_HOST:localhost}:${REGISTRY_PORT:8761}/eureka/
5 |
6 | hystrix:
7 | command:
8 | default:
9 | execution:
10 | isolation:
11 | thread:
12 | timeoutInMilliseconds: 20000
13 |
14 | ribbon:
15 | ReadTimeout: 20000
16 | ConnectTimeout: 20000
17 |
18 | zuul:
19 | ignoredServices: '*'
20 | host:
21 | connect-timeout-millis: 20000
22 | socket-timeout-millis: 20000
23 |
24 | routes:
25 | account:
26 | path: /restful/accounts/**
27 | serviceId: account
28 | stripPrefix: false
29 | sensitiveHeaders: "*"
30 |
31 | payment:
32 | path: /restful/pay/**
33 | serviceId: payment
34 | stripPrefix: false
35 | sensitiveHeaders: "*"
36 |
37 | settlement:
38 | path: /restful/settlements/**
39 | serviceId: payment
40 | stripPrefix: false
41 | sensitiveHeaders: "*"
42 |
43 | advertisements:
44 | path: /restful/advertisements/**
45 | serviceId: warehouse
46 | stripPrefix: false
47 | sensitiveHeaders: "*"
48 |
49 | products:
50 | path: /restful/products/**
51 | serviceId: warehouse
52 | stripPrefix: false
53 | sensitiveHeaders: "*"
54 |
55 | security:
56 | path: /oauth/**
57 | serviceId: security
58 | stripPrefix: false
59 | sensitiveHeaders: "*"
60 |
61 | server:
62 | port: ${PORT:8080}
63 |
64 | logging:
65 | level:
66 | root: INFO
67 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/resources/configurations/payment.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${REGISTRY_HOST:localhost}:${REGISTRY_PORT:8761}/eureka/
5 |
6 | spring:
7 | cache:
8 | type: redis
9 | redis:
10 | cache-null-values: false
11 | time-to-live: PT5M
12 | datasource:
13 | schema: "classpath:db/schema.sql"
14 | data: "classpath:db/data.sql"
15 | sql-script-encoding: UTF-8
16 | driverClassName: "com.mysql.cj.jdbc.Driver"
17 | url: ${MYSQL_URL:jdbc:mysql://localhost/mmall?useUnicode=true&characterEncoding=utf-8}
18 | username: "root"
19 | password: "root1234"
20 | initialization-mode: always
21 | jpa:
22 | show-sql: true
23 | hibernate:
24 | ddl-auto: none
25 | open-in-view: true
26 | generate-ddl: false
27 | database: mysql
28 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
29 | resources:
30 | chain:
31 | compressed: true
32 | cache: true
33 | cache:
34 | period: 86400
35 | redis:
36 | host: ${REDIS_HOST:localhost}
37 | port: ${REDIS_PORT:6379}
38 |
39 | logging:
40 | pattern:
41 | console: "%clr(%d{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:%5p}) %clr(-){faint} %clr([%t]){faint} %clr(%-40logger{39}){cyan}[%line]%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}"
42 | level:
43 | root: INFO
44 | com.github.kay: DEBUG
45 |
46 | security:
47 | oauth2:
48 | client:
49 | # OAuth的ClientID和ClientSecret是写在OAuthClientDetailsService中的
50 | # 实际生产中要考虑好如何获取验证服务器的Endpoint、动态增加微服务客户端、如何分发客户端密钥等问题,而在演示工程中并不关注这些
51 | clientId: account
52 | clientSecret: account_secret
53 | accessTokenUri: http://${AUTH_HOST:localhost}:${AUTH_PORT:8301}/oauth/token
54 | grant-type: client_credentials
55 | scope: SERVICE
56 | resource:
57 | userInfoUri: BUGFIX
58 |
59 | server:
60 | port: ${PORT:8601}
61 |
62 | mmall:
63 | redisson-config: "redisson-config.yml"
64 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/resources/configurations/registry.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: ${PORT:8761}
3 |
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/resources/configurations/security.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${REGISTRY_HOST:localhost}:${REGISTRY_PORT:8761}/eureka/
5 |
6 | server:
7 | port: ${PORT:8301}
8 |
9 | security:
10 | oauth2:
11 | client:
12 | # OAuth的ClientID和ClientSecret是写在OAuthClientDetailsService中的
13 | # 实际生产中要考虑好如何获取验证服务器的Endpoint、动态增加微服务客户端、如何分发客户端密钥等问题,而在演示工程中并不关注这些
14 | clientId: security
15 | clientSecret: security_secret
16 | accessTokenUri: http://localhost:${PORT:8301}/oauth/token
17 | grant-type: client_credentials
18 | scope: SERVICE
19 |
20 | logging:
21 | pattern:
22 | console: "%clr(%d{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:%5p}) %clr(-){faint} %clr([%t]){faint} %clr(%-40logger{39}){cyan}[%line]%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}"
23 | level:
24 | root: INFO
25 |
26 | spring:
27 | cache:
28 | type: none
29 |
30 | mmall:
31 | redisson:
32 | enabled: false
--------------------------------------------------------------------------------
/mmall-platform-configuration/src/main/resources/configurations/warehouse.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${REGISTRY_HOST:localhost}:${REGISTRY_PORT:8761}/eureka/
5 |
6 | spring:
7 | cache:
8 | type: redis
9 | redis:
10 | cache-null-values: false
11 | time-to-live: PT5M
12 | datasource:
13 | schema: "classpath:db/schema.sql"
14 | data: "classpath:db/data.sql"
15 | sql-script-encoding: UTF-8
16 | url: ${MYSQL_URL:jdbc:mysql://localhost/mmall?useUnicode=true&characterEncoding=utf-8}
17 | username: "root"
18 | password: "root1234"
19 | initialization-mode: always
20 | jpa:
21 | show-sql: true
22 | hibernate:
23 | ddl-auto: none
24 | open-in-view: true
25 | generate-ddl: false
26 | database: mysql
27 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
28 | resources:
29 | chain:
30 | compressed: true
31 | cache: true
32 | cache:
33 | period: 86400
34 | redis:
35 | host: ${REDIS_HOST:localhost}
36 | port: ${REDIS_PORT:6379}
37 |
38 | logging:
39 | pattern:
40 | console: "%clr(%d{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:%5p}) %clr(-){faint} %clr([%t]){faint} %clr(%-40logger{39}){cyan}[%line]%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}"
41 | level:
42 | root: INFO
43 | com.github.kay: DEBUG
44 |
45 | security:
46 | oauth2:
47 | client:
48 | # OAuth的ClientID和ClientSecret是写在OAuthClientDetailsService中的
49 | # 实际生产中要考虑好如何获取验证服务器的Endpoint、动态增加微服务客户端、如何分发客户端密钥等问题,而在演示工程中并不关注这些
50 | clientId: account
51 | clientSecret: account_secret
52 | accessTokenUri: http://${AUTH_HOST:localhost}:${AUTH_PORT:8301}/oauth/token
53 | grant-type: client_credentials
54 | scope: SERVICE
55 | resource:
56 | userInfoUri: BUGFIX
57 |
58 | server:
59 | port: ${PORT:8501}
60 |
61 | mmall:
62 | redisson-config: "redisson-config.yml"
63 |
--------------------------------------------------------------------------------
/mmall-platform-gateway/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:12-alpine
2 |
3 | MAINTAINER kaybee
4 |
5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
6 | JAVA_OPTS="" \
7 | PORT=8080 \
8 | CONFIG_PORT=8888 \
9 | PROFILES="default"
10 |
11 | ADD /build/libs/*.jar /mmall-gateway.jar
12 |
13 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /mmall-gateway.jar --spring.profiles.active=$PROFILES"]
14 |
15 | EXPOSE $PORT
--------------------------------------------------------------------------------
/mmall-platform-gateway/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'org.springframework.boot'
4 | id 'io.spring.dependency-management'
5 | }
6 |
7 |
8 | dependencies {
9 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
10 | implementation 'org.springframework.cloud:spring-cloud-starter-config'
11 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/mmall-platform-gateway/src/main/java/com/github/kay/mmall/GatewayApplication.java:
--------------------------------------------------------------------------------
1 | package com.github.kay.mmall;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
7 |
8 | @EnableZuulProxy
9 | @EnableDiscoveryClient
10 | @SpringBootApplication
11 | public class GatewayApplication {
12 | public static void main(String[] args) {
13 | SpringApplication.run(GatewayApplication.class, args);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/mmall-platform-gateway/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: gateway
4 | cloud:
5 | config:
6 | uri: http://${CONFIG_HOST:localhost}:${CONFIG_PORT:8888}
7 | fail-fast: true
8 | password: ${CONFIG_PASS:dev}
9 | username: user
10 |
--------------------------------------------------------------------------------
/mmall-platform-gateway/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 |