├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .travis.yml ├── LICENSE ├── README.md ├── bookstore-microservices-domain-account ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── fenixsoft │ │ │ └── bookstore │ │ │ └── account │ │ │ ├── AccountApplication.java │ │ │ ├── application │ │ │ └── AccountApplicationService.java │ │ │ ├── domain │ │ │ ├── AccountRepository.java │ │ │ └── validation │ │ │ │ ├── AccountValidation.java │ │ │ │ ├── AuthenticatedAccount.java │ │ │ │ ├── ExistsAccount.java │ │ │ │ ├── NotConflictAccount.java │ │ │ │ └── UniqueAccount.java │ │ │ └── resource │ │ │ └── AccountResource.java │ └── resources │ │ ├── application-test.yml │ │ ├── banner.txt │ │ ├── bootstrap.yml │ │ ├── db │ │ ├── hsqldb │ │ │ ├── data.sql │ │ │ └── schema.sql │ │ └── mysql │ │ │ ├── data.sql │ │ │ ├── schema.sql │ │ │ └── user.sql │ │ └── public.cert │ └── test │ └── java │ └── com │ └── github │ └── fenixsoft │ └── bookstore │ └── account │ └── AccountResourceTest.java ├── bookstore-microservices-domain-payment ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── fenixsoft │ │ │ └── bookstore │ │ │ └── paymnet │ │ │ ├── PaymentApplication.java │ │ │ ├── application │ │ │ └── PaymentApplicationService.java │ │ │ ├── domain │ │ │ ├── Payment.java │ │ │ ├── Wallet.java │ │ │ ├── client │ │ │ │ └── ProductServiceClient.java │ │ │ ├── repository │ │ │ │ ├── CacheRepository.java │ │ │ │ ├── PaymentRepository.java │ │ │ │ └── WalletRepository.java │ │ │ ├── service │ │ │ │ ├── PaymentService.java │ │ │ │ └── WalletService.java │ │ │ └── validation │ │ │ │ ├── SettlementValidator.java │ │ │ │ └── SufficientStock.java │ │ │ └── resource │ │ │ ├── PaymentResource.java │ │ │ └── SettlementResource.java │ └── resources │ │ ├── application-test.yml │ │ ├── banner.txt │ │ ├── bootstrap.yml │ │ ├── db │ │ ├── hsqldb │ │ │ ├── data.sql │ │ │ └── schema.sql │ │ └── mysql │ │ │ ├── data.sql │ │ │ ├── schema.sql │ │ │ └── user.sql │ │ └── public.cert │ └── test │ └── java │ └── com │ └── github │ └── fenixsoft │ └── bookstore │ └── paymnet │ ├── PaymentResourceTest.java │ └── mock │ └── ProductServiceClientMock.java ├── bookstore-microservices-domain-security ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── fenixsoft │ │ │ └── bookstore │ │ │ └── security │ │ │ ├── SecurityApplication.java │ │ │ ├── configuration │ │ │ ├── AuthenticationServerConfiguration.java │ │ │ ├── AuthorizationServerConfiguration.java │ │ │ └── WebSecurityConfiguration.java │ │ │ └── provider │ │ │ ├── PreAuthenticatedAuthenticationProvider.java │ │ │ ├── RSA256JWTAccessToken.java │ │ │ └── UsernamePasswordAuthenticationProvider.java │ └── resources │ │ ├── application-test.yml │ │ ├── banner.txt │ │ ├── bootstrap.yml │ │ ├── db │ │ └── hsqldb │ │ │ ├── data.sql │ │ │ └── schema.sql │ │ ├── public.cert │ │ └── rsa.jks │ └── test │ └── java │ └── com │ └── github │ └── fenixsoft │ └── bookstore │ └── security │ └── AuthResourceTest.java ├── bookstore-microservices-domain-warehouse ├── Dockerfile ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── fenixsoft │ │ │ └── bookstore │ │ │ └── warehouse │ │ │ ├── WarehouseApplication.java │ │ │ ├── application │ │ │ ├── ProductApplicationService.java │ │ │ └── StockpileApplicationService.java │ │ │ ├── domain │ │ │ ├── Advertisement.java │ │ │ ├── AdvertisementRepository.java │ │ │ ├── ProductRepository.java │ │ │ ├── ProductService.java │ │ │ ├── StockpileRepository.java │ │ │ └── StockpileService.java │ │ │ └── resource │ │ │ ├── AdvertisementResource.java │ │ │ ├── ProductResource.java │ │ │ └── StockpileResource.java │ └── resources │ │ ├── application-test.yml │ │ ├── banner.txt │ │ ├── bootstrap.yml │ │ ├── db │ │ ├── hsqldb │ │ │ ├── data.sql │ │ │ └── schema.sql │ │ └── mysql │ │ │ ├── data.sql │ │ │ ├── schema.sql │ │ │ └── user.sql │ │ └── public.cert │ └── test │ └── java │ └── com │ └── github │ └── fenixsoft │ └── bookstore │ └── warehouse │ ├── AdvertisementResourceTest.java │ └── ProductResourceTest.java ├── bookstore-microservices-library-infrastructure ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── fenixsoft │ └── bookstore │ ├── domain │ ├── BaseEntity.java │ ├── account │ │ └── Account.java │ ├── security │ │ ├── AccountServiceClient.java │ │ ├── AuthenticAccount.java │ │ ├── AuthenticAccountDetailsService.java │ │ ├── AuthenticAccountRepository.java │ │ ├── GrantType.java │ │ ├── Role.java │ │ └── Scope.java │ └── warehouse │ │ ├── DeliveredStatus.java │ │ ├── Product.java │ │ ├── Specification.java │ │ └── Stockpile.java │ ├── dto │ ├── Item.java │ ├── Purchase.java │ └── Settlement.java │ └── infrastructure │ ├── cache │ └── CacheConfiguration.java │ ├── configuration │ ├── FeignConfiguration.java │ ├── JPAConfiguration.java │ ├── JerseyConfiguration.java │ └── ResourceServerConfiguration.java │ ├── jaxrs │ ├── AccessDeniedExceptionMapper.java │ ├── BaseExceptionMapper.java │ ├── CodedMessage.java │ ├── CommonResponse.java │ └── ViolationExceptionMapper.java │ ├── security │ ├── HS256JWTAccessToken.java │ ├── JWTAccessToken.java │ ├── JWTAccessTokenService.java │ ├── OAuthClientDetailsService.java │ └── RSA256PublicJWTAccessToken.java │ └── utility │ └── Encryption.java ├── bookstore-microservices-library-testing ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── fenixsoft │ └── bookstore │ └── resource │ ├── DBRollbackBase.java │ ├── JAXRSResourceBase.java │ └── mock │ └── AccountServiceClientMock.java ├── bookstore-microservices-platform-configuration ├── Dockerfile ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── fenixsoft │ │ └── bookstore │ │ └── configuration │ │ └── ConfigApplication.java │ └── resources │ ├── application.yml │ ├── banner.txt │ └── configurations │ ├── account.yml │ ├── gateway.yml │ ├── payment.yml │ ├── registry.yml │ ├── security.yml │ └── warehouse.yml ├── bookstore-microservices-platform-gateway ├── Dockerfile ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── fenixsoft │ │ └── bookstore │ │ └── gateway │ │ └── GatewayApplication.java │ └── resources │ ├── banner.txt │ ├── bootstrap.yml │ └── static │ ├── favicon.ico │ ├── index.html │ └── static │ ├── board │ ├── gitalk.css │ ├── gitalk.html │ └── gitalk.min.js │ ├── carousel │ ├── ai.png │ ├── fenix.png │ ├── fenix2.png │ └── jvm3.png │ ├── cover │ ├── ai.jpg │ ├── fenix.png │ ├── jvm1.jpg │ ├── jvm2.jpg │ ├── jvm3.jpg │ ├── jvms.jpg │ ├── jvms8.jpg │ └── osgi.jpg │ ├── css │ ├── app.13440f960e43a3574b009b7352447f18.css │ └── app.acff6d0da14b65448084a2639e44b2ef.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 │ └── logo-gray-light.84aa074.png │ └── js │ ├── 0.c178f427b3d08777c70f.js │ ├── 1.a33faf036923758c7965.js │ ├── 1.adddfb80b9441d8bc19d.js │ ├── 2.626ed94f3752555e21f0.js │ ├── 3.bc7f0b2154007257c317.js │ ├── 4.b4e48a42cf742af20851.js │ ├── 5.d375cbd6c7e1463cdbed.js │ ├── 6.68562501db5734ef1531.js │ ├── 7.184a5e39cc0c624f6a6d.js │ ├── 8.176f9455c3442c06ebf6.js │ ├── 9.527be297aba1594ffe0d.js │ ├── app.ea66dc0be78c3ed2ae63.js │ ├── manifest.0437a7f02d3154ee1abb.js │ ├── manifest.1aeebcd3a724536ddb12.js │ └── vendor.c2f13a2146485051ae24.js ├── bookstore-microservices-platform-registry ├── Dockerfile ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── fenixsoft │ │ └── bookstore │ │ └── registry │ │ └── RegistryApplication.java │ └── resources │ ├── banner.txt │ └── bootstrap.yml ├── bookstore-microservices-report-aggregation └── pom.xml ├── docker-compose.dev.yml ├── docker-compose.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── travis_docker_push.sh /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - openjdk12 4 | before_install: 5 | - export TZ='Asia/Shanghai' 6 | install: 7 | - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V 8 | script: 9 | - mvn clean test package coveralls:report -DrepoToken=$repoToken 10 | # - mvn clean package 11 | deploy: 12 | - provider: script 13 | keep_history: true 14 | skip_cleanup: true 15 | script: bash travis_docker_push.sh 16 | on: 17 | branch: master 18 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | 3 | MAINTAINER icyfenix 4 | 5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ 6 | JAVA_OPTS="" \ 7 | PORT=8401 \ 8 | CONFIG_PORT=8888 \ 9 | AUTH_PORT=8301 \ 10 | PROFILES="default" 11 | 12 | ADD /target/*.jar /bookstore-account.jar 13 | 14 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /bookstore-account.jar --spring.profiles.active=$PROFILES"] 15 | 16 | EXPOSE $PORT 17 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-domain-account 13 | 14 | 15 | 16 | com.github.fenixsoft 17 | bookstore-microservices-library-infrastructure 18 | 1.0.0-SNAPSHOT 19 | 20 | 21 | com.github.fenixsoft 22 | bookstore-microservices-library-testing 23 | 1.0.0-SNAPSHOT 24 | test 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-maven-plugin 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/AccountApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account; 20 | 21 | import org.springframework.boot.SpringApplication; 22 | import org.springframework.boot.autoconfigure.SpringBootApplication; 23 | import org.springframework.cache.annotation.EnableCaching; 24 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 25 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 26 | 27 | @EnableCaching 28 | @EnableDiscoveryClient 29 | @SpringBootApplication(scanBasePackages = {"com.github.fenixsoft.bookstore"}) 30 | public class AccountApplication { 31 | public static void main(String[] args) { 32 | SpringApplication.run(AccountApplication.class, args); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/application/AccountApplicationService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account.application; 20 | 21 | import com.github.fenixsoft.bookstore.account.domain.AccountRepository; 22 | import com.github.fenixsoft.bookstore.domain.account.Account; 23 | import com.github.fenixsoft.bookstore.infrastructure.utility.Encryption; 24 | 25 | import javax.inject.Inject; 26 | import javax.inject.Named; 27 | import javax.transaction.Transactional; 28 | 29 | /** 30 | * 用户资源的应用服务接口 31 | * 32 | * @author icyfenix@gmail.com 33 | * @date 2020/3/10 17:46 34 | **/ 35 | @Named 36 | @Transactional 37 | public class AccountApplicationService { 38 | 39 | @Inject 40 | private AccountRepository repository; 41 | 42 | @Inject 43 | private Encryption encoder; 44 | 45 | public void createAccount(Account account) { 46 | account.setPassword(encoder.encode(account.getPassword())); 47 | repository.save(account); 48 | } 49 | 50 | public Account findAccountByUsername(String username) { 51 | return repository.findByUsername(username); 52 | } 53 | 54 | public void updateAccount(Account account) { 55 | repository.save(account); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/domain/AccountRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account.domain; 20 | 21 | import com.github.fenixsoft.bookstore.domain.account.Account; 22 | import com.sun.xml.bind.v2.model.core.ID; 23 | import org.springframework.cache.annotation.CacheConfig; 24 | import org.springframework.cache.annotation.CacheEvict; 25 | import org.springframework.cache.annotation.Cacheable; 26 | import org.springframework.cache.annotation.Caching; 27 | import org.springframework.data.repository.CrudRepository; 28 | 29 | import java.util.Collection; 30 | import java.util.Optional; 31 | 32 | /** 33 | * 用户对象数据仓库 34 | * 35 | * @author icyfenix@gmail.com 36 | * @date 2020/3/6 23:10 37 | **/ 38 | @CacheConfig(cacheNames = "repository.account") 39 | public interface AccountRepository extends CrudRepository { 40 | 41 | @Override 42 | Iterable findAll(); 43 | 44 | 45 | @Cacheable(key = "#username") 46 | Account findByUsername(String username); 47 | 48 | /** 49 | * 判断唯一性,用户名、邮箱、电话不允许任何一个重复 50 | */ 51 | boolean existsByUsernameOrEmailOrTelephone(String username, String email, String telephone); 52 | 53 | /** 54 | * 判断唯一性,用户名、邮箱、电话不允许任何一个重复 55 | */ 56 | Collection findByUsernameOrEmailOrTelephone(String username, String email, String telephone); 57 | 58 | /** 59 | * 判断存在性,用户名存在即为存在 60 | */ 61 | @Cacheable(key = "#username") 62 | boolean existsByUsername(String username); 63 | 64 | 65 | // 覆盖以下父类中需要处理缓存失效的方法 66 | // 父类取不到CacheConfig的配置信息,所以不能抽象成一个通用的父类接口中完成 67 | @Caching(evict = { 68 | @CacheEvict(key = "#entity.id"), 69 | @CacheEvict(key = "#entity.username") 70 | }) 71 | S save(S entity); 72 | 73 | @CacheEvict 74 | Iterable saveAll(Iterable entities); 75 | 76 | @Cacheable(key = "#id") 77 | Optional findById(ID id); 78 | 79 | @Cacheable(key = "#id") 80 | boolean existsById(ID id); 81 | 82 | @CacheEvict(key = "#id") 83 | void deleteById(ID id); 84 | 85 | @CacheEvict(key = "#entity.id") 86 | void delete(Account entity); 87 | 88 | @CacheEvict(allEntries = true) 89 | void deleteAll(Iterable entities); 90 | 91 | @CacheEvict(allEntries = true) 92 | void deleteAll(); 93 | } 94 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/domain/validation/AuthenticatedAccount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account.domain.validation; 20 | 21 | import javax.validation.Constraint; 22 | import javax.validation.Payload; 23 | import java.lang.annotation.Documented; 24 | import java.lang.annotation.Retention; 25 | import java.lang.annotation.Target; 26 | 27 | import static java.lang.annotation.ElementType.*; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | /** 31 | * 代表用户必须与当前登陆的用户一致 32 | * 相当于使用Spring Security的@PreAuthorize("#{user.name == authentication.name}")的验证 33 | * 34 | * @author icyfenix@gmail.com 35 | * @date 2020/3/16 11:06 36 | **/ 37 | @Documented 38 | @Retention(RUNTIME) 39 | @Target({FIELD, METHOD, PARAMETER, TYPE}) 40 | @Constraint(validatedBy = AccountValidation.AuthenticatedAccountValidator.class) 41 | public @interface AuthenticatedAccount { 42 | String message() default "不是当前登陆用户"; 43 | 44 | Class[] groups() default {}; 45 | 46 | Class[] payload() default {}; 47 | } 48 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/domain/validation/ExistsAccount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account.domain.validation; 20 | 21 | import javax.validation.Constraint; 22 | import javax.validation.Payload; 23 | import java.lang.annotation.Documented; 24 | import java.lang.annotation.Retention; 25 | import java.lang.annotation.Target; 26 | 27 | import static java.lang.annotation.ElementType.*; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | /** 31 | * 代表一个用户在数据仓库中是存在的 32 | * 33 | * @author icyfenix@gmail.com 34 | * @date 2020/3/11 19:51 35 | **/ 36 | @Documented 37 | @Retention(RUNTIME) 38 | @Target({FIELD, METHOD, PARAMETER, TYPE}) 39 | @Constraint(validatedBy = AccountValidation.ExistsAccountValidator.class) 40 | public @interface ExistsAccount { 41 | String message() default "用户不存在"; 42 | 43 | Class[] groups() default {}; 44 | 45 | Class[] payload() default {}; 46 | } 47 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/domain/validation/NotConflictAccount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account.domain.validation; 20 | 21 | import javax.validation.Constraint; 22 | import javax.validation.Payload; 23 | import java.lang.annotation.Documented; 24 | import java.lang.annotation.Retention; 25 | import java.lang.annotation.Target; 26 | 27 | import static java.lang.annotation.ElementType.*; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | /** 31 | * 表示一个用户的信息是无冲突的 32 | *

33 | * “无冲突”是指该用户的敏感信息与其他用户不重合,譬如将一个注册用户的邮箱,修改成与另外一个已存在的注册用户一致的值,这便是冲突 34 | * 35 | * @author icyfenix@gmail.com 36 | * @date 2020/3/11 20:19 37 | **/ 38 | @Documented 39 | @Retention(RUNTIME) 40 | @Target({FIELD, METHOD, PARAMETER, TYPE}) 41 | @Constraint(validatedBy = AccountValidation.NotConflictAccountValidator.class) 42 | public @interface NotConflictAccount { 43 | String message() default "用户名称、邮箱、手机号码与现存用户产生重复"; 44 | 45 | Class[] groups() default {}; 46 | 47 | Class[] payload() default {}; 48 | } 49 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/domain/validation/UniqueAccount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account.domain.validation; 20 | 21 | import javax.validation.Constraint; 22 | import javax.validation.Payload; 23 | import java.lang.annotation.Documented; 24 | import java.lang.annotation.Retention; 25 | import java.lang.annotation.Target; 26 | 27 | import static java.lang.annotation.ElementType.*; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | /** 31 | * 表示一个用户是唯一的 32 | *

33 | * 唯一不仅仅是用户名,还要求手机、邮箱均不允许重复 34 | * 35 | * @author icyfenix@gmail.com 36 | * @date 2020/3/11 19:49 37 | **/ 38 | @Documented 39 | @Retention(RUNTIME) 40 | @Target({FIELD, METHOD, PARAMETER, TYPE}) 41 | @Constraint(validatedBy = AccountValidation.UniqueAccountValidator.class) 42 | public @interface UniqueAccount { 43 | String message() default "用户名称、邮箱、手机号码均不允许与现存用户重复"; 44 | 45 | Class[] groups() default {}; 46 | 47 | Class[] payload() default {}; 48 | } 49 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/java/com/github/fenixsoft/bookstore/account/resource/AccountResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.account.resource; 20 | 21 | import com.github.fenixsoft.bookstore.account.application.AccountApplicationService; 22 | import com.github.fenixsoft.bookstore.account.domain.validation.AuthenticatedAccount; 23 | import com.github.fenixsoft.bookstore.account.domain.validation.UniqueAccount; 24 | import com.github.fenixsoft.bookstore.domain.account.Account; 25 | import com.github.fenixsoft.bookstore.account.domain.validation.NotConflictAccount; 26 | import com.github.fenixsoft.bookstore.infrastructure.jaxrs.CommonResponse; 27 | import org.springframework.cache.annotation.CacheConfig; 28 | import org.springframework.cache.annotation.CacheEvict; 29 | import org.springframework.cache.annotation.Cacheable; 30 | import org.springframework.security.access.prepost.PreAuthorize; 31 | import org.springframework.stereotype.Component; 32 | 33 | import javax.inject.Inject; 34 | import javax.validation.Valid; 35 | import javax.ws.rs.*; 36 | import javax.ws.rs.core.MediaType; 37 | import javax.ws.rs.core.Response; 38 | 39 | /** 40 | * 用户资源 41 | *

42 | * 对客户端以Restful形式暴露资源,提供对用户资源{@link Account}的管理入口 43 | * 44 | * @author icyfenix@gmail.com 45 | * @date 2020/3/6 20:52 46 | **/ 47 | @Path("/accounts") 48 | @Component 49 | @CacheConfig(cacheNames = "resource.account") 50 | @Produces(MediaType.APPLICATION_JSON) 51 | @Consumes(MediaType.APPLICATION_JSON) 52 | public class AccountResource { 53 | 54 | @Inject 55 | private AccountApplicationService service; 56 | 57 | /** 58 | * 根据用户名称获取用户详情 59 | */ 60 | @GET 61 | @Path("/{username}") 62 | @Cacheable(key = "#username") 63 | @PreAuthorize("#oauth2.hasAnyScope('SERVICE','BROWSER')") 64 | public Account getUser(@PathParam("username") String username) { 65 | return service.findAccountByUsername(username); 66 | } 67 | 68 | /** 69 | * 创建新的用户 70 | */ 71 | @POST 72 | @CacheEvict(key = "#user.username") 73 | public Response createUser(@Valid @UniqueAccount Account user) { 74 | return CommonResponse.op(() -> service.createAccount(user)); 75 | } 76 | 77 | /** 78 | * 更新用户信息 79 | */ 80 | @PUT 81 | @CacheEvict(key = "#user.username") 82 | @PreAuthorize("#oauth2.hasAnyScope('BROWSER')") 83 | public Response updateUser(@Valid @AuthenticatedAccount @NotConflictAccount Account user) { 84 | return CommonResponse.op(() -> service.updateAccount(user)); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | enabled: false 4 | 5 | database: hsqldb 6 | 7 | spring: 8 | datasource: 9 | schema: "classpath:db/${database}/schema.sql" 10 | data: "classpath:db/${database}/data.sql" 11 | sql-script-encoding: UTF-8 12 | jpa: 13 | show-sql: false 14 | hibernate: 15 | ddl-auto: none 16 | open-in-view: false 17 | resources: 18 | chain: 19 | compressed: true 20 | cache: true 21 | cache: 22 | period: 86400 23 | 24 | logging: 25 | pattern: 26 | 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}" 27 | level: 28 | root: INFO 29 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ______ _ ____ __ _____ __ 2 | / ____/__ ____ (_) __ / __ )____ ____ / /_/ ___// /_____ ________ 3 | / /_ / _ \/ __ \/ / |/_/ / __ / __ \/ __ \/ __/\__ \/ __/ __ \/ ___/ _ \ 4 | / __/ / __/ / / / /> < / /_/ / /_/ / /_/ / /_ ___/ / /_/ /_/ / / / __/ 5 | /_/ \___/_/ /_/_/_/|_| /_____/\____/\____/\__//____/\__/\____/_/ \___/ 6 | Account Domain 7 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: account 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 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/db/hsqldb/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO account VALUES (1, 'icyfenix', '$2a$10$iIim4LtpT2yjxU2YVNDuO.yb1Z2lq86vYBZleAeuIh2aFXjyoMCM.' , '周志明', '', '18888888888', 'icyfenix@gmail.com', '唐家湾港湾大道科技一路3号远光软件股份有限公司'); 2 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/db/hsqldb/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE account IF EXISTS; 2 | 3 | CREATE TABLE account 4 | ( 5 | id INTEGER IDENTITY PRIMARY KEY, 6 | username VARCHAR(50), 7 | password VARCHAR(100), 8 | name VARCHAR(50), 9 | avatar VARCHAR(100), 10 | telephone VARCHAR(20), 11 | email VARCHAR(100), 12 | location VARCHAR(100) 13 | ); 14 | CREATE UNIQUE INDEX account_user ON account (username); 15 | CREATE UNIQUE INDEX account_telephone ON account (telephone); 16 | CREATE UNIQUE INDEX account_email ON account (email); 17 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/db/mysql/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO account 2 | VALUES (1, 'icyfenix', '$2a$10$LTqKTXXRb26SYG3MvFG1UuKhMgc/i6IbUl2RgApiWd39y1EqlXbD6', '周志明', '', '18888888888', 3 | 'icyfenix@gmail.com', '唐家湾港湾大道科技一路3号远光软件股份有限公司'); 4 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/db/mysql/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS account; 2 | 3 | CREATE TABLE IF NOT EXISTS account 4 | ( 5 | id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 6 | username VARCHAR(50), 7 | password VARCHAR(100), 8 | name VARCHAR(50), 9 | avatar VARCHAR(100), 10 | telephone VARCHAR(20), 11 | email VARCHAR(100), 12 | location VARCHAR(100), 13 | INDEX (username) 14 | ) engine = InnoDB; 15 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/db/mysql/user.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS bookstore; 2 | 3 | ALTER DATABASE bookstore 4 | DEFAULT CHARACTER SET utf8 5 | DEFAULT COLLATE utf8_general_ci; 6 | 7 | GRANT ALL PRIVILEGES ON bookstore.* TO 'bookstore@%' IDENTIFIED BY 'bookstore'; 8 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/main/resources/public.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi+htQPOTvNMccJjOkCAz 3 | d3YlqBElURzkaeRLDoJYskyU59JdGO+p/q4JEH0DZOM2BbonGI4lIHFkiZLO4IBB 4 | Z5j2P7U6QYURt6+AyjS6RGw9v/wFdIRlyBI9D3EO7u8rCA4RktBLPavfEc5BwYX2 5 | Vb9wX6N63tV48cP1CoGU0GtIq9HTqbEQs5KVmme5n4XOuzxQ6B2AGaPBJgdq/K0Z 6 | WDkXiqPz6921X3oiNYPCQ22bvFxb4yFX8ZfbxeYc+1rN7PaUsK009qOx+qRenHpW 7 | gPVfagMbNYkm0TOHNOWXqukxE+soCDI/Nc++1khWCmQ9E2B82ap7IXsVBAnBIaV9 8 | WQIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /bookstore-microservices-domain-account/src/test/java/com/github/fenixsoft/bookstore/account/AccountResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.account; 2 | 3 | import com.github.fenixsoft.bookstore.domain.account.Account; 4 | import com.github.fenixsoft.bookstore.resource.JAXRSResourceBase; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import javax.ws.rs.core.Response; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | /** 12 | * @author icyfenix@gmail.com 13 | * @date 2020/4/6 18:52 14 | **/ 15 | class AccountResourceTest extends JAXRSResourceBase { 16 | 17 | @Test 18 | void getUserWithExistAccount() { 19 | Response resp = get("/accounts/icyfenix"); 20 | assertForbidden(resp); 21 | authenticatedScope(() -> { 22 | Response resp2 = get("/accounts/icyfenix"); 23 | Account icyfenix = resp2.readEntity(Account.class); 24 | assertEquals("icyfenix", icyfenix.getUsername(), "should return user: icyfenix"); 25 | }); 26 | } 27 | 28 | @Test 29 | void getUserWithNotExistAccount() { 30 | authenticatedScope(() -> assertNoContent(get("/accounts/nobody"))); 31 | 32 | } 33 | 34 | @Test 35 | void createUser() { 36 | authenticatedScope(() -> { 37 | Account newbee = new Account(); 38 | newbee.setUsername("newbee"); 39 | newbee.setEmail("newbee@github.com"); 40 | assertBadRequest(post("/accounts", newbee)); 41 | newbee.setTelephone("13888888888"); 42 | newbee.setName("somebody"); 43 | assertNoContent(get("/accounts/newbee")); 44 | assertOK(post("/accounts", newbee)); 45 | assertOK(get("/accounts/newbee")); 46 | }); 47 | } 48 | 49 | @Test 50 | void updateUser() { 51 | authenticatedScope(() -> { 52 | Response resp = get("/accounts/icyfenix"); 53 | Account icyfenix = resp.readEntity(Account.class); 54 | icyfenix.setName("zhouzhiming"); 55 | assertOK(put("/accounts", icyfenix)); 56 | assertEquals("zhouzhiming", get("/accounts/icyfenix").readEntity(Account.class).getName(), "should get the new name now"); 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | 3 | MAINTAINER icyfenix 4 | 5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ 6 | JAVA_OPTS="" \ 7 | PORT=8601 \ 8 | CONFIG_PORT=8888 \ 9 | AUTH_PORT=8301 \ 10 | PROFILES="default" 11 | 12 | ADD /target/*.jar /bookstore-payment.jar 13 | 14 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /bookstore-payment.jar --spring.profiles.active=$PROFILES"] 15 | 16 | EXPOSE $PORT 17 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-domain-payment 13 | 14 | 15 | 16 | com.github.fenixsoft 17 | bookstore-microservices-library-infrastructure 18 | 1.0.0-SNAPSHOT 19 | 20 | 21 | com.github.fenixsoft 22 | bookstore-microservices-library-testing 23 | 1.0.0-SNAPSHOT 24 | test 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-maven-plugin 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/PaymentApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.paymnet; 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.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 7 | 8 | @EnableDiscoveryClient 9 | @SpringBootApplication(scanBasePackages = {"com.github.fenixsoft.bookstore"}) 10 | public class PaymentApplication { 11 | public static void main(String[] args) { 12 | SpringApplication.run(PaymentApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/application/PaymentApplicationService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.application; 20 | 21 | import com.github.fenixsoft.bookstore.paymnet.domain.Payment; 22 | import com.github.fenixsoft.bookstore.paymnet.domain.client.ProductServiceClient; 23 | import com.github.fenixsoft.bookstore.paymnet.domain.service.PaymentService; 24 | import com.github.fenixsoft.bookstore.paymnet.domain.service.WalletService; 25 | import com.github.fenixsoft.bookstore.dto.Settlement; 26 | import org.springframework.cache.Cache; 27 | 28 | import javax.annotation.Resource; 29 | import javax.inject.Inject; 30 | import javax.inject.Named; 31 | import javax.transaction.Transactional; 32 | 33 | /** 34 | * 支付应用务 35 | * 36 | * @author icyfenix@gmail.com 37 | * @date 2020/3/12 16:29 38 | **/ 39 | @Named 40 | @Transactional 41 | public class PaymentApplicationService { 42 | 43 | @Inject 44 | private PaymentService paymentService; 45 | 46 | @Inject 47 | private WalletService walletService; 48 | 49 | @Inject 50 | private ProductServiceClient productService; 51 | 52 | @Resource(name = "settlement") 53 | private Cache settlementCache; 54 | 55 | /** 56 | * 根据结算清单的内容执行,生成对应的支付单 57 | */ 58 | public Payment executeBySettlement(Settlement bill) { 59 | // 从服务中获取商品的价格,计算要支付的总价(安全原因,这个不能由客户端传上来) 60 | productService.replenishProductInformation(bill); 61 | // 冻结部分库存(保证有货提供),生成付款单 62 | Payment payment = paymentService.producePayment(bill); 63 | // 设立解冻定时器(超时未支付则释放冻结的库存和资金) 64 | paymentService.setupAutoThawedTrigger(payment); 65 | return payment; 66 | } 67 | 68 | /** 69 | * 完成支付 70 | * 立即取消解冻定时器,执行扣减库存和资金 71 | */ 72 | public void accomplishPayment(Integer accountId, String payId) { 73 | // 订单从冻结状态变为派送状态,扣减库存 74 | double price = paymentService.accomplish(payId); 75 | try { 76 | // 扣减货款 77 | walletService.decrease(accountId, price); 78 | } catch (Throwable e) { 79 | // 扣款失败,将已支付的记录回滚恢复库存 80 | paymentService.rollbackSettlement(Payment.State.PAYED, payId); 81 | throw e; 82 | } 83 | // 支付成功的清除缓存 84 | settlementCache.evict(payId); 85 | } 86 | 87 | /** 88 | * 取消支付 89 | * 立即触发解冻定时器,释放库存和资金 90 | */ 91 | public void cancelPayment(String payId) { 92 | // 释放冻结的库存 93 | paymentService.cancel(payId); 94 | // 支付成功的清除缓存 95 | settlementCache.evict(payId); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/Wallet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.domain; 20 | 21 | import com.github.fenixsoft.bookstore.domain.BaseEntity; 22 | import com.github.fenixsoft.bookstore.domain.account.Account; 23 | 24 | import javax.persistence.Entity; 25 | import javax.persistence.FetchType; 26 | import javax.persistence.JoinColumn; 27 | import javax.persistence.OneToOne; 28 | 29 | /** 30 | * 用户钱包 31 | * 32 | * @author icyfenix@gmail.com 33 | * @date 2020/3/12 16:30 34 | **/ 35 | 36 | @Entity 37 | public class Wallet extends BaseEntity { 38 | 39 | public Wallet() { 40 | // for JPA 41 | } 42 | 43 | public Wallet(Integer accountId, Double money) { 44 | setAccountId(accountId); 45 | setMoney(money); 46 | } 47 | 48 | // 这里是偷懒,正式项目中请使用BigDecimal来表示金额 49 | private Double money; 50 | 51 | private Integer accountId; 52 | 53 | public Double getMoney() { 54 | return money; 55 | } 56 | 57 | public void setMoney(Double money) { 58 | this.money = money; 59 | } 60 | 61 | public Integer getAccountId() { 62 | return accountId; 63 | } 64 | 65 | public void setAccountId(Integer accountId) { 66 | this.accountId = accountId; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/client/ProductServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.paymnet.domain.client; 2 | 3 | import com.github.fenixsoft.bookstore.domain.warehouse.DeliveredStatus; 4 | import com.github.fenixsoft.bookstore.domain.warehouse.Product; 5 | import com.github.fenixsoft.bookstore.domain.warehouse.Stockpile; 6 | import com.github.fenixsoft.bookstore.dto.Settlement; 7 | import org.springframework.cloud.openfeign.FeignClient; 8 | 9 | import javax.ws.rs.*; 10 | import javax.ws.rs.core.MediaType; 11 | import java.util.function.Function; 12 | import java.util.stream.Collectors; 13 | import java.util.stream.Stream; 14 | 15 | /** 16 | * 仓库商品和库存相关远程服务 17 | * 18 | * @author icyfenix@gmail.com 19 | * @date 2020/4/19 22:22 20 | **/ 21 | @FeignClient(name = "warehouse") 22 | public interface ProductServiceClient { 23 | 24 | default void replenishProductInformation(Settlement bill) { 25 | bill.productMap = Stream.of(getProducts()).collect(Collectors.toMap(Product::getId, Function.identity())); 26 | } 27 | 28 | @GET 29 | @Path("/restful/products/{id}") 30 | @Consumes(MediaType.APPLICATION_JSON) 31 | Product getProduct(@PathParam("id") Integer id); 32 | 33 | @GET 34 | @Path("/restful/products") 35 | @Consumes(MediaType.APPLICATION_JSON) 36 | Product[] getProducts(); 37 | 38 | default void decrease(Integer productId, Integer amount) { 39 | setDeliveredStatus(productId, DeliveredStatus.DECREASE, amount); 40 | } 41 | 42 | default void increase(Integer productId, Integer amount) { 43 | setDeliveredStatus(productId, DeliveredStatus.INCREASE, amount); 44 | } 45 | 46 | default void frozen(Integer productId, Integer amount) { 47 | setDeliveredStatus(productId, DeliveredStatus.FROZEN, amount); 48 | } 49 | 50 | default void thawed(Integer productId, Integer amount) { 51 | setDeliveredStatus(productId, DeliveredStatus.THAWED, amount); 52 | } 53 | 54 | @PATCH 55 | @Path("/restful/products/stockpile/delivered/{productId}") 56 | @Consumes(MediaType.APPLICATION_JSON) 57 | void setDeliveredStatus(@PathParam("productId") Integer productId, @QueryParam("status") DeliveredStatus status, @QueryParam("amount") Integer amount); 58 | 59 | @GET 60 | @Path("/restful/products/stockpile/{productId}") 61 | @Consumes(MediaType.APPLICATION_JSON) 62 | Stockpile queryStockpile(@PathParam("productId") Integer productId); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/repository/CacheRepository.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.paymnet.domain.repository; 2 | 3 | import com.github.benmanes.caffeine.cache.Caffeine; 4 | import org.springframework.cache.Cache; 5 | import org.springframework.cache.caffeine.CaffeineCache; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | import java.util.concurrent.TimeUnit; 10 | 11 | import static com.github.fenixsoft.bookstore.infrastructure.cache.CacheConfiguration.SYSTEM_DEFAULT_EXPIRES; 12 | 13 | /** 14 | * 业务过程中使用到缓存的数据仓库 15 | * 16 | * @author icyfenix@gmail.com 17 | * @date 2020/4/20 9:21 18 | **/ 19 | @Configuration 20 | public class CacheRepository { 21 | @Bean(name = "settlement") 22 | public Cache getSettlementTTLCache() { 23 | return new CaffeineCache("settlement", Caffeine.newBuilder().expireAfterAccess(SYSTEM_DEFAULT_EXPIRES, TimeUnit.MILLISECONDS).build()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/repository/PaymentRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.domain.repository; 20 | 21 | import com.github.fenixsoft.bookstore.paymnet.domain.Payment; 22 | import org.springframework.data.repository.CrudRepository; 23 | 24 | /** 25 | * 支付单数据仓库 26 | * 27 | * @author icyfenix@gmail.com 28 | * @date 2020/3/12 23:25 29 | **/ 30 | public interface PaymentRepository extends CrudRepository { 31 | 32 | Payment getByPayId(String payId); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/repository/WalletRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.domain.repository; 20 | 21 | import com.github.fenixsoft.bookstore.paymnet.domain.Wallet; 22 | import org.springframework.data.repository.CrudRepository; 23 | 24 | import java.util.Optional; 25 | 26 | /** 27 | * 钱包数据仓库 28 | * 29 | * @author icyfenix@gmail.com 30 | * @date 2020/3/12 16:35 31 | **/ 32 | public interface WalletRepository extends CrudRepository { 33 | 34 | Optional findByAccountId(Integer accountId); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/service/WalletService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.domain.service; 20 | 21 | import com.github.fenixsoft.bookstore.paymnet.domain.Wallet; 22 | import com.github.fenixsoft.bookstore.paymnet.domain.repository.WalletRepository; 23 | import com.github.fenixsoft.bookstore.domain.account.Account; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import javax.inject.Inject; 28 | import javax.inject.Named; 29 | 30 | /** 31 | * 用户钱包的领域服务 32 | *

33 | * 由于本工程中冻结、解冻款项的方法是为了在微服务中演示TCC事务所准备的,单体服务中由于与本地事务一同提交,无需用到 34 | * 35 | * @author icyfenix@gmail.com 36 | * @date 2020/3/12 20:23 37 | **/ 38 | @Named 39 | public class WalletService { 40 | 41 | private static final Logger log = LoggerFactory.getLogger(WalletService.class); 42 | 43 | @Inject 44 | private WalletRepository repository; 45 | 46 | /** 47 | * 账户资金减少 48 | */ 49 | public void decrease(Integer accountId, Double amount) { 50 | Wallet wallet = repository.findByAccountId(accountId).orElseGet(() -> repository.save(new Wallet(accountId, 0D))); 51 | if (wallet.getMoney() > amount) { 52 | wallet.setMoney(wallet.getMoney() - amount); 53 | repository.save(wallet); 54 | log.info("支付成功。用户余额:{},本次消费:{}", wallet.getMoney(), amount); 55 | } else { 56 | throw new RuntimeException("用户余额不足以支付,请先充值"); 57 | } 58 | } 59 | 60 | /** 61 | * 账户资金增加(演示程序,没有做充值入口,实际这个方法无用) 62 | */ 63 | public void increase(Integer accountId, Double amount) { 64 | } 65 | 66 | // 以下两个方法是为TCC事务准备的,在单体架构中不需要实现 67 | 68 | /** 69 | * 账户资金冻结 70 | * 从正常资金中移动指定数量至冻结状态 71 | */ 72 | public void frozen(Integer accountId, Double amount) { 73 | } 74 | 75 | /** 76 | * 账户资金解冻 77 | * 从冻结资金中移动指定数量至正常状态 78 | */ 79 | public void thawed(Integer accountId, Double amount) { 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/validation/SettlementValidator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.domain.validation; 20 | 21 | import javax.inject.Inject; 22 | 23 | import com.github.fenixsoft.bookstore.paymnet.domain.client.ProductServiceClient; 24 | import com.github.fenixsoft.bookstore.dto.Settlement; 25 | 26 | import javax.validation.ConstraintValidator; 27 | import javax.validation.ConstraintValidatorContext; 28 | 29 | /** 30 | * 结算单验证器 31 | *

32 | * 结算单能够成功执行的约束是清单中每一项商品的库存量都足够。 33 | *

34 | * 这个验证器的目的不在于保证商品高并发情况(如秒杀活动)下不超卖,而在于避免库存不足时仍可下单。高并发下的超卖是一种“不可重复读”现象 35 | * (即读取过的数据在事务期间被另一个事务改变),如要严谨地避免,需要把数据库的隔离级别从默认的“Read Committed”提升至“Repeatable Read” 36 | * 除了MySQL(InnoDB)外,主流的数据库,如Oracle、SQLServer默认都是Read committed,提升隔离级别会显著影响数据库的并发能力。 37 | * 38 | * @author icyfenix@gmail.com 39 | * @date 2020/3/16 9:02 40 | **/ 41 | public class SettlementValidator implements ConstraintValidator { 42 | 43 | @Inject 44 | private ProductServiceClient service; 45 | 46 | @Override 47 | public boolean isValid(Settlement value, ConstraintValidatorContext context) { 48 | return value.getItems().stream().noneMatch(i -> service.queryStockpile(i.getProductId()).getAmount() < i.getAmount()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/domain/validation/SufficientStock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.domain.validation; 20 | 21 | import javax.validation.Constraint; 22 | import javax.validation.Payload; 23 | import java.lang.annotation.Documented; 24 | import java.lang.annotation.Retention; 25 | import java.lang.annotation.Target; 26 | 27 | import static java.lang.annotation.ElementType.*; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | /** 31 | * 判断结算单中货物存量是充足的 32 | * 33 | * @author icyfenix@gmail.com 34 | * @date 2020/3/16 8:59 35 | **/ 36 | @Documented 37 | @Retention(RUNTIME) 38 | @Target({FIELD, METHOD, PARAMETER, TYPE}) 39 | @Constraint(validatedBy = SettlementValidator.class) 40 | public @interface SufficientStock { 41 | String message() default "商品库存不足"; 42 | 43 | Class[] groups() default {}; 44 | 45 | Class[] payload() default {}; 46 | } 47 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/resource/PaymentResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.resource; 20 | 21 | import com.github.fenixsoft.bookstore.domain.account.Account; 22 | import com.github.fenixsoft.bookstore.infrastructure.jaxrs.CommonResponse; 23 | import com.github.fenixsoft.bookstore.domain.security.Role; 24 | import com.github.fenixsoft.bookstore.paymnet.application.PaymentApplicationService; 25 | import com.github.fenixsoft.bookstore.paymnet.domain.Payment; 26 | import org.springframework.security.core.context.SecurityContextHolder; 27 | import org.springframework.stereotype.Component; 28 | 29 | import javax.annotation.security.RolesAllowed; 30 | import javax.inject.Inject; 31 | import javax.ws.rs.*; 32 | import javax.ws.rs.core.MediaType; 33 | import javax.ws.rs.core.Response; 34 | 35 | /** 36 | * 支付单相关的资源 37 | * 38 | * @author icyfenix@gmail.com 39 | * @date 2020/3/13 12:52 40 | **/ 41 | @Path("/pay") 42 | @Component 43 | @Produces(MediaType.APPLICATION_JSON) 44 | public class PaymentResource { 45 | 46 | @Inject 47 | private PaymentApplicationService service; 48 | 49 | /** 50 | * 修改支付单据的状态 51 | */ 52 | @PATCH 53 | @Path("/{payId}") 54 | @RolesAllowed(Role.USER) 55 | public Response updatePaymentState(@PathParam("payId") String payId, @QueryParam("state") Payment.State state) { 56 | Account account = (Account) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 57 | return updatePaymentStateAlias(payId, account.getId(), state); 58 | } 59 | 60 | /** 61 | * 修改支付单状态的GET方法别名 62 | * 考虑到该动作要由二维码扫描来触发,只能进行GET请求,所以增加一个别名以便通过二维码调用 63 | * 这个方法原本应该作为银行支付接口的回调,不控制调用权限(谁付款都行),但都认为是购买用户付的款 64 | */ 65 | @GET 66 | @Path("/modify/{payId}") 67 | public Response updatePaymentStateAlias(@PathParam("payId") String payId, @QueryParam("accountId") Integer accountId, @QueryParam("state") Payment.State state) { 68 | if (state == Payment.State.PAYED) { 69 | return CommonResponse.op(() -> service.accomplishPayment(accountId, payId)); 70 | } else { 71 | return CommonResponse.op(() -> service.cancelPayment(payId)); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/java/com/github/fenixsoft/bookstore/paymnet/resource/SettlementResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.paymnet.resource; 20 | 21 | import com.github.fenixsoft.bookstore.dto.Settlement; 22 | import com.github.fenixsoft.bookstore.paymnet.application.PaymentApplicationService; 23 | import com.github.fenixsoft.bookstore.paymnet.domain.Payment; 24 | import com.github.fenixsoft.bookstore.paymnet.domain.validation.SufficientStock; 25 | import com.github.fenixsoft.bookstore.domain.security.Role; 26 | import org.springframework.stereotype.Component; 27 | 28 | import javax.annotation.security.RolesAllowed; 29 | import javax.inject.Inject; 30 | import javax.validation.Valid; 31 | import javax.ws.rs.Consumes; 32 | import javax.ws.rs.POST; 33 | import javax.ws.rs.Path; 34 | import javax.ws.rs.Produces; 35 | import javax.ws.rs.core.MediaType; 36 | 37 | /** 38 | * 结算清单相关的资源 39 | * 40 | * @author icyfenix@gmail.com 41 | * @date 2020/3/12 11:23 42 | **/ 43 | @Path("/settlements") 44 | @Component 45 | @Produces(MediaType.APPLICATION_JSON) 46 | @Consumes(MediaType.APPLICATION_JSON) 47 | public class SettlementResource { 48 | 49 | @Inject 50 | private PaymentApplicationService service; 51 | 52 | /** 53 | * 提交一张交易结算单,根据结算单中的物品,生成支付单 54 | */ 55 | @POST 56 | @RolesAllowed(Role.USER) 57 | public Payment executeSettlement(@Valid @SufficientStock Settlement settlement) { 58 | return service.executeBySettlement(settlement); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | enabled: false 4 | 5 | database: hsqldb 6 | 7 | spring: 8 | datasource: 9 | schema: "classpath:db/${database}/schema.sql" 10 | data: "classpath:db/${database}/data.sql" 11 | sql-script-encoding: UTF-8 12 | jpa: 13 | show-sql: false 14 | hibernate: 15 | ddl-auto: none 16 | open-in-view: false 17 | resources: 18 | chain: 19 | compressed: true 20 | cache: true 21 | cache: 22 | period: 86400 23 | 24 | logging: 25 | pattern: 26 | 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}" 27 | level: 28 | root: INFO 29 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ______ _ ____ __ _____ __ 2 | / ____/__ ____ (_) __ / __ )____ ____ / /_/ ___// /_____ ________ 3 | / /_ / _ \/ __ \/ / |/_/ / __ / __ \/ __ \/ __/\__ \/ __/ __ \/ ___/ _ \ 4 | / __/ / __/ / / / /> < / /_/ / /_/ / /_/ / /_ ___/ / /_/ /_/ / / / __/ 5 | /_/ \___/_/ /_/_/_/|_| /_____/\____/\____/\__//____/\__/\____/_/ \___/ 6 | Payment Domain 7 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: payment 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 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/db/hsqldb/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO wallet VALUES (1, 300, 1); 2 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/db/hsqldb/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE wallet IF EXISTS; 2 | DROP TABLE payment IF EXISTS; 3 | 4 | CREATE TABLE wallet 5 | ( 6 | id INTEGER IDENTITY PRIMARY KEY, 7 | money DECIMAL, 8 | account_id INTEGER 9 | ); 10 | 11 | CREATE TABLE payment 12 | ( 13 | id INTEGER IDENTITY PRIMARY KEY, 14 | pay_id VARCHAR(100), 15 | create_time DATETIME, 16 | total_price DECIMAL, 17 | expires INTEGER NOT NULL, 18 | payment_link VARCHAR(300), 19 | pay_state VARCHAR(20) 20 | ); 21 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/db/mysql/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO wallet 2 | VALUES (1, 100, 1); 3 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/db/mysql/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS payment; 2 | DROP TABLE IF EXISTS wallet; 3 | 4 | CREATE TABLE IF NOT EXISTS wallet 5 | ( 6 | id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 7 | money DECIMAL, 8 | account_id INTEGER UNSIGNED 9 | ) engine = InnoDB; 10 | 11 | CREATE TABLE IF NOT EXISTS payment 12 | ( 13 | id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 14 | pay_id VARCHAR(100), 15 | create_time DATETIME, 16 | total_price DECIMAL, 17 | expires INTEGER NOT NULL, 18 | payment_link VARCHAR(300), 19 | pay_state VARCHAR(20) 20 | ) engine = InnoDB; 21 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/db/mysql/user.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS bookstore; 2 | 3 | ALTER DATABASE bookstore 4 | DEFAULT CHARACTER SET utf8 5 | DEFAULT COLLATE utf8_general_ci; 6 | 7 | GRANT ALL PRIVILEGES ON bookstore.* TO 'bookstore@%' IDENTIFIED BY 'bookstore'; 8 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/main/resources/public.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi+htQPOTvNMccJjOkCAz 3 | d3YlqBElURzkaeRLDoJYskyU59JdGO+p/q4JEH0DZOM2BbonGI4lIHFkiZLO4IBB 4 | Z5j2P7U6QYURt6+AyjS6RGw9v/wFdIRlyBI9D3EO7u8rCA4RktBLPavfEc5BwYX2 5 | Vb9wX6N63tV48cP1CoGU0GtIq9HTqbEQs5KVmme5n4XOuzxQ6B2AGaPBJgdq/K0Z 6 | WDkXiqPz6921X3oiNYPCQ22bvFxb4yFX8ZfbxeYc+1rN7PaUsK009qOx+qRenHpW 7 | gPVfagMbNYkm0TOHNOWXqukxE+soCDI/Nc++1khWCmQ9E2B82ap7IXsVBAnBIaV9 8 | WQIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/test/java/com/github/fenixsoft/bookstore/paymnet/PaymentResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.paymnet; 2 | 3 | import com.github.fenixsoft.bookstore.dto.Item; 4 | import com.github.fenixsoft.bookstore.dto.Purchase; 5 | import com.github.fenixsoft.bookstore.dto.Settlement; 6 | import com.github.fenixsoft.bookstore.paymnet.domain.Payment; 7 | import com.github.fenixsoft.bookstore.resource.JAXRSResourceBase; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import javax.ws.rs.core.Response; 11 | 12 | import java.util.Collections; 13 | 14 | import static org.junit.jupiter.api.Assertions.*; 15 | 16 | /** 17 | * @author icyfenix@gmail.com 18 | * @date 2020/4/21 17:04 19 | **/ 20 | class PaymentResourceTest extends JAXRSResourceBase { 21 | 22 | private Settlement createSettlement() { 23 | Settlement settlement = new Settlement(); 24 | Item item = new Item(); 25 | Purchase purchase = new Purchase(); 26 | settlement.setItems(Collections.singletonList(item)); 27 | settlement.setPurchase(purchase); 28 | item.setAmount(2); 29 | item.setProductId(1); 30 | purchase.setLocation("xx rd. zhuhai. guangdong. china"); 31 | purchase.setName("icyfenix"); 32 | purchase.setPay("wechat"); 33 | purchase.setTelephone("18888888888"); 34 | return settlement; 35 | } 36 | 37 | @Test 38 | void executeSettlement() { 39 | final Settlement settlement = createSettlement(); 40 | assertForbidden(post("/settlements", settlement)); 41 | authenticatedScope(() -> { 42 | Response response = post("/settlements", settlement); 43 | assertOK(response); 44 | Payment payment = response.readEntity(Payment.class); 45 | assertNotNull(payment.getPayId()); 46 | }); 47 | } 48 | 49 | @Test 50 | void updatePaymentState() { 51 | final Settlement settlement = createSettlement(); 52 | authenticatedScope(() -> { 53 | Payment payment = post("/settlements", settlement).readEntity(Payment.class); 54 | assertOK(patch("/pay/" + payment.getPayId() + "?state=PAYED")); 55 | assertServerError(patch("/pay/" + payment.getPayId() + "?state=CANCEL")); 56 | payment = post("/settlements", settlement).readEntity(Payment.class); // another 57 | assertOK(patch("/pay/" + payment.getPayId() + "?state=CANCEL")); 58 | assertServerError(patch("/pay/" + payment.getPayId() + "?state=NOT_SUPPORT")); 59 | }); 60 | } 61 | 62 | @Test 63 | void updatePaymentStateAlias() { 64 | Payment payment = authenticatedGetter(() -> post("/settlements", createSettlement()).readEntity(Payment.class)); 65 | assertOK(get(payment.getPaymentLink())); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-payment/src/test/java/com/github/fenixsoft/bookstore/paymnet/mock/ProductServiceClientMock.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.paymnet.mock; 2 | 3 | import com.github.fenixsoft.bookstore.domain.warehouse.DeliveredStatus; 4 | import com.github.fenixsoft.bookstore.domain.warehouse.Product; 5 | import com.github.fenixsoft.bookstore.domain.warehouse.Stockpile; 6 | import com.github.fenixsoft.bookstore.paymnet.domain.client.ProductServiceClient; 7 | 8 | import javax.inject.Named; 9 | 10 | /** 11 | * @author icyfenix@gmail.com 12 | * @date 2020/4/21 17:07 13 | **/ 14 | @Named 15 | public class ProductServiceClientMock implements ProductServiceClient { 16 | 17 | @Override 18 | public Product getProduct(Integer id) { 19 | if (id == 1) { 20 | Product product = new Product(); 21 | product.setId(1); 22 | product.setTitle("深入理解Java虚拟机(第3版)"); 23 | product.setPrice(129d); 24 | product.setRate(9.6f); 25 | return product; 26 | } else { 27 | return null; 28 | } 29 | } 30 | 31 | @Override 32 | public Product[] getProducts() { 33 | return new Product[]{getProduct(1)}; 34 | } 35 | 36 | @Override 37 | public void setDeliveredStatus(Integer productId, DeliveredStatus status, Integer amount) { 38 | } 39 | 40 | @Override 41 | public Stockpile queryStockpile(Integer productId) { 42 | if (productId == 1) { 43 | Stockpile stock = new Stockpile(); 44 | stock.setId(1); 45 | stock.setAmount(30); 46 | stock.setProduct(getProduct(1)); 47 | return stock; 48 | } else { 49 | return null; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | 3 | MAINTAINER icyfenix 4 | 5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ 6 | JAVA_OPTS="" \ 7 | PORT=8301 \ 8 | CONFIG_PORT=8888 \ 9 | PROFILES="default" 10 | 11 | ADD /target/*.jar /bookstore-security.jar 12 | 13 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /bookstore-security.jar --spring.profiles.active=$PROFILES"] 14 | 15 | EXPOSE $PORT 16 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-domain-security 13 | 14 | 15 | 16 | com.github.fenixsoft 17 | bookstore-microservices-library-infrastructure 18 | 1.0.0-SNAPSHOT 19 | 20 | 21 | com.github.fenixsoft 22 | bookstore-microservices-library-testing 23 | 1.0.0-SNAPSHOT 24 | test 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-maven-plugin 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/java/com/github/fenixsoft/bookstore/security/SecurityApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.security; 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.openfeign.EnableFeignClients; 7 | 8 | /** 9 | * SprintCloud Security 认证、授权服务 10 | * 11 | * @author icyfenix@gmail.com 12 | * @date 2020/4/18 11:17 13 | **/ 14 | @EnableDiscoveryClient 15 | @SpringBootApplication(scanBasePackages = {"com.github.fenixsoft.bookstore"}) 16 | public class SecurityApplication { 17 | public static void main(String[] args) { 18 | SpringApplication.run(SecurityApplication.class, args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/java/com/github/fenixsoft/bookstore/security/configuration/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.security.configuration; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | 8 | /** 9 | * Spring Security安全配置 10 | *

11 | * 移除静态资源目录的安全控制,避免Spring Security默认禁止HTTP缓存的行为 12 | * 13 | * @author icyfenix@gmail.com 14 | * @date 2020/4/8 0:09 15 | **/ 16 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 17 | 18 | @Override 19 | protected void configure(HttpSecurity http) throws Exception { 20 | http.headers().cacheControl().disable(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/java/com/github/fenixsoft/bookstore/security/provider/PreAuthenticatedAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.security.provider; 20 | 21 | import com.github.fenixsoft.bookstore.domain.security.AuthenticAccount; 22 | import org.springframework.security.authentication.AuthenticationProvider; 23 | import org.springframework.security.authentication.DisabledException; 24 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 25 | import org.springframework.security.core.Authentication; 26 | import org.springframework.security.core.AuthenticationException; 27 | import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; 28 | import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException; 29 | 30 | import javax.inject.Named; 31 | 32 | /** 33 | * 预验证身份认证器 34 | *

35 | * 预验证是指身份已经在其他地方(第三方)确认过 36 | * 预验证器的目的是将第三方身份管理系统集成到具有Spring安全性的Spring应用程序中,在本项目中,用于JWT令牌过期后重刷新时的验证 37 | * 此时只要检查用户是否有停用、锁定、密码过期、账号过期等问题,如果没有,可根据JWT令牌的刷新过期期限,重新给客户端发放访问令牌 38 | * 39 | * @author icyfenix@gmail.com 40 | * @date 2020/3/10 11:25 41 | * @see Pre-Authentication Scenarios 42 | **/ 43 | @Named 44 | public class PreAuthenticatedAuthenticationProvider implements AuthenticationProvider { 45 | 46 | @Override 47 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 48 | if (authentication.getPrincipal() instanceof UsernamePasswordAuthenticationToken) { 49 | AuthenticAccount user = (AuthenticAccount) ((UsernamePasswordAuthenticationToken) authentication.getPrincipal()).getPrincipal(); 50 | // 检查用户没有停用、锁定、密码过期、账号过期等问题 51 | // 在本项目中这些功能都未启用,实际上此检查肯定是会通过的,但为了严谨和日后扩展,还是依次进行了检查 52 | if (user.isEnabled() && user.isCredentialsNonExpired() && user.isAccountNonExpired() && user.isCredentialsNonExpired()) { 53 | return new PreAuthenticatedAuthenticationToken(user, "", user.getAuthorities()); 54 | } else { 55 | throw new DisabledException("用户状态不正确"); 56 | } 57 | } else { 58 | throw new PreAuthenticatedCredentialsNotFoundException("预验证失败,传上来的令牌是怎么来的?"); 59 | } 60 | } 61 | 62 | /** 63 | * 判断该验证器能处理哪些认证 64 | */ 65 | @Override 66 | public boolean supports(Class clazz) { 67 | return clazz.equals(PreAuthenticatedAuthenticationToken.class); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/java/com/github/fenixsoft/bookstore/security/provider/RSA256JWTAccessToken.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.security.provider; 2 | 3 | import com.github.fenixsoft.bookstore.infrastructure.security.JWTAccessToken; 4 | import org.springframework.context.annotation.Primary; 5 | import org.springframework.core.io.ClassPathResource; 6 | import org.springframework.security.core.userdetails.UserDetailsService; 7 | import org.springframework.security.jwt.JwtHelper; 8 | import org.springframework.security.jwt.crypto.sign.Signer; 9 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 10 | import org.springframework.security.oauth2.common.util.JsonParser; 11 | import org.springframework.security.oauth2.common.util.JsonParserFactory; 12 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 13 | import org.springframework.security.rsa.crypto.KeyStoreKeyFactory; 14 | import org.springframework.util.ReflectionUtils; 15 | 16 | import javax.inject.Named; 17 | import java.lang.reflect.Field; 18 | import java.util.Collections; 19 | import java.util.Map; 20 | 21 | /** 22 | * 使用RSA SHA256私钥加密的JWT令牌 23 | *

24 | * 在Infrastructure工程中提供了{@link com.github.fenixsoft.bookstore.infrastructure.security.RSA256PublicJWTAccessToken}作为公钥验证用途。 25 | * 为了便于对比, 26 | * 27 | * @author icyfenix@gmail.com 28 | * @date 2020/7/17 15:02 29 | **/ 30 | @Named 31 | @Primary 32 | public class RSA256JWTAccessToken extends JWTAccessToken { 33 | 34 | private final JsonParser objectMapper = JsonParserFactory.create(); 35 | 36 | RSA256JWTAccessToken(UserDetailsService userDetailsService) { 37 | super(userDetailsService); 38 | KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("rsa.jks"), "123456".toCharArray()); 39 | setKeyPair(keyStoreKeyFactory.getKeyPair("fenix-bookstore-rsa")); 40 | } 41 | 42 | /** 43 | * 增强令牌Header 44 | * 使用JWKS验证令牌时,Header中需要有kid(Key ID),设置Header的方法在Spring的默认实现中没有开放出来,这里添加个默认处理 45 | */ 46 | @Override 47 | protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { 48 | Field signerField = ReflectionUtils.findField(this.getClass(), "signer"); 49 | signerField.setAccessible(true); 50 | Signer signer = (Signer) ReflectionUtils.getField(signerField, this); 51 | 52 | String content; 53 | try { 54 | content = this.objectMapper.formatMap(getAccessTokenConverter().convertAccessToken(accessToken, authentication)); 55 | } catch (Exception ex) { 56 | throw new IllegalStateException("Cannot convert access token to JSON", ex); 57 | } 58 | 59 | Map headers = Collections.singletonMap("kid", "bookstore-jwt-kid"); 60 | return JwtHelper.encode(content, signer, headers).getEncoded(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/java/com/github/fenixsoft/bookstore/security/provider/UsernamePasswordAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.security.provider; 20 | 21 | import com.github.fenixsoft.bookstore.domain.security.AuthenticAccountDetailsService; 22 | import org.springframework.security.authentication.AuthenticationManager; 23 | import org.springframework.security.authentication.AuthenticationProvider; 24 | import org.springframework.security.authentication.BadCredentialsException; 25 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 26 | import org.springframework.security.core.Authentication; 27 | import org.springframework.security.core.AuthenticationException; 28 | import org.springframework.security.core.userdetails.UserDetails; 29 | import org.springframework.security.crypto.password.PasswordEncoder; 30 | 31 | import javax.inject.Inject; 32 | import javax.inject.Named; 33 | 34 | /** 35 | * 基于用户名、密码的身份认证器 36 | * 该身份认证器会被{@link AuthenticationManager}验证管理器调用 37 | * 验证管理器支持多种验证方式,这里基于用户名、密码的的身份认证是方式之一 38 | * 39 | * @author icyfenix@gmail.com 40 | * @date 2020/3/7 21:45 41 | */ 42 | @Named 43 | public class UsernamePasswordAuthenticationProvider implements AuthenticationProvider { 44 | 45 | @Inject 46 | private AuthenticAccountDetailsService authenticAccountDetailsService; 47 | 48 | @Inject 49 | private PasswordEncoder passwordEncoder; 50 | 51 | /** 52 | * 认证处理 53 | *

54 | * 根据用户名查询用户资料,对比资料中加密后的密码 55 | * 结果将返回一个Authentication的实现类(此处为UsernamePasswordAuthenticationToken)则代表认证成功 56 | * 返回null或者抛出AuthenticationException的子类异常则代表认证失败 57 | */ 58 | @Override 59 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 60 | String username = authentication.getName().toLowerCase(); 61 | String password = (String) authentication.getCredentials(); 62 | // AuthenticationException的子类定义了多种认证失败的类型,这里仅处“理用户不存在”、“密码不正确”两种 63 | // 用户不存在的话会直接由loadUserByUsername()抛出异常 64 | UserDetails user = authenticAccountDetailsService.loadUserByUsername(username); 65 | if (!passwordEncoder.matches(password, user.getPassword())) throw new BadCredentialsException("密码不正确"); 66 | // 认证通过,返回令牌 67 | return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities()); 68 | 69 | } 70 | 71 | /** 72 | * 判断该验证器能处理哪些认证 73 | */ 74 | @Override 75 | public boolean supports(Class clazz) { 76 | return clazz.equals(UsernamePasswordAuthenticationToken.class); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | enabled: false 4 | 5 | spring: 6 | datasource: 7 | initialization-mode: never 8 | 9 | logging: 10 | pattern: 11 | 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}" 12 | level: 13 | root: INFO 14 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ______ _ ____ __ _____ __ 2 | / ____/__ ____ (_) __ / __ )____ ____ / /_/ ___// /_____ ________ 3 | / /_ / _ \/ __ \/ / |/_/ / __ / __ \/ __ \/ __/\__ \/ __/ __ \/ ___/ _ \ 4 | / __/ / __/ / / / /> < / /_/ / /_/ / /_/ / /_ ___/ / /_/ /_/ / / / __/ 5 | /_/ \___/_/ /_/_/_/|_| /_____/\____/\____/\__//____/\__/\____/_/ \___/ 6 | Service Security 7 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: security 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 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/resources/db/hsqldb/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO account VALUES (1, 'icyfenix', '$2a$10$iIim4LtpT2yjxU2YVNDuO.yb1Z2lq86vYBZleAeuIh2aFXjyoMCM.' , '周志明', '', '18888888888', 'icyfenix@gmail.com', '唐家湾港湾大道科技一路3号远光软件股份有限公司'); 2 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/resources/db/hsqldb/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE account IF EXISTS; 2 | 3 | CREATE TABLE account 4 | ( 5 | id INTEGER IDENTITY PRIMARY KEY, 6 | username VARCHAR(50), 7 | password VARCHAR(100), 8 | name VARCHAR(50), 9 | avatar VARCHAR(100), 10 | telephone VARCHAR(20), 11 | email VARCHAR(100), 12 | location VARCHAR(100) 13 | ); 14 | CREATE UNIQUE INDEX account_user ON account (username); 15 | CREATE UNIQUE INDEX account_telephone ON account (telephone); 16 | CREATE UNIQUE INDEX account_email ON account (email); 17 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/resources/public.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi+htQPOTvNMccJjOkCAz 3 | d3YlqBElURzkaeRLDoJYskyU59JdGO+p/q4JEH0DZOM2BbonGI4lIHFkiZLO4IBB 4 | Z5j2P7U6QYURt6+AyjS6RGw9v/wFdIRlyBI9D3EO7u8rCA4RktBLPavfEc5BwYX2 5 | Vb9wX6N63tV48cP1CoGU0GtIq9HTqbEQs5KVmme5n4XOuzxQ6B2AGaPBJgdq/K0Z 6 | WDkXiqPz6921X3oiNYPCQ22bvFxb4yFX8ZfbxeYc+1rN7PaUsK009qOx+qRenHpW 7 | gPVfagMbNYkm0TOHNOWXqukxE+soCDI/Nc++1khWCmQ9E2B82ap7IXsVBAnBIaV9 8 | WQIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/main/resources/rsa.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-domain-security/src/main/resources/rsa.jks -------------------------------------------------------------------------------- /bookstore-microservices-domain-security/src/test/java/com/github/fenixsoft/bookstore/security/AuthResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.security; 2 | 3 | import com.github.fenixsoft.bookstore.resource.JAXRSResourceBase; 4 | import org.json.JSONException; 5 | import org.json.JSONObject; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import javax.ws.rs.client.ClientBuilder; 10 | import javax.ws.rs.core.Response; 11 | 12 | /** 13 | * @author icyfenix@gmail.com 14 | * @date 2020/4/7 16:47 15 | **/ 16 | public class AuthResourceTest extends JAXRSResourceBase { 17 | 18 | @Test 19 | void refreshToken() throws JSONException { 20 | String prefix = "http://localhost:" + port + "/oauth/token?"; 21 | String url = prefix + "username=icyfenix&password=MFfTW3uNI4eqhwDkG7HP9p2mzEUu%2Fr2&grant_type=password&client_id=bookstore_frontend&client_secret=bookstore_secret"; 22 | Response resp = ClientBuilder.newClient().target(url).request().get(); 23 | String refreshToken = json(resp).getString("refresh_token"); 24 | url = prefix + "refresh_token=" + refreshToken + "&grant_type=refresh_token&client_id=bookstore_frontend&client_secret=bookstore_secret"; 25 | resp = ClientBuilder.newClient().target(url).request().get(); 26 | String accessToken = json(resp).getString("access_token"); 27 | Assertions.assertNotNull(accessToken); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | 3 | MAINTAINER icyfenix 4 | 5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ 6 | JAVA_OPTS="" \ 7 | PORT=8501 \ 8 | CONFIG_PORT=8888 \ 9 | AUTH_PORT=8301 \ 10 | PROFILES="default" 11 | 12 | ADD /target/*.jar /bookstore-warehouse.jar 13 | 14 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /bookstore-warehouse.jar --spring.profiles.active=$PROFILES"] 15 | 16 | EXPOSE $PORT 17 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-domain-warehouse 13 | 14 | 15 | 16 | com.github.fenixsoft 17 | bookstore-microservices-library-infrastructure 18 | 1.0.0-SNAPSHOT 19 | 20 | 21 | com.github.fenixsoft 22 | bookstore-microservices-library-testing 23 | 1.0.0-SNAPSHOT 24 | test 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-maven-plugin 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/WarehouseApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse; 20 | 21 | import org.springframework.boot.SpringApplication; 22 | import org.springframework.boot.autoconfigure.SpringBootApplication; 23 | import org.springframework.cache.annotation.EnableCaching; 24 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 25 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 26 | 27 | @EnableCaching 28 | @EnableDiscoveryClient 29 | @SpringBootApplication(scanBasePackages = {"com.github.fenixsoft.bookstore"}) 30 | public class WarehouseApplication { 31 | public static void main(String[] args) { 32 | SpringApplication.run(WarehouseApplication.class, args); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/application/ProductApplicationService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse.application; 20 | 21 | import com.github.fenixsoft.bookstore.domain.warehouse.Product; 22 | import com.github.fenixsoft.bookstore.warehouse.domain.ProductService; 23 | 24 | import javax.inject.Inject; 25 | import javax.inject.Named; 26 | import javax.transaction.Transactional; 27 | 28 | /** 29 | * 产品的应用服务接口 30 | * 31 | * @author icyfenix@gmail.com 32 | * @date 2020/3/15 20:05 33 | **/ 34 | @Named 35 | @Transactional 36 | public class ProductApplicationService { 37 | 38 | @Inject 39 | private ProductService service; 40 | 41 | /** 42 | * 获取仓库中所有的货物信息 43 | */ 44 | public Iterable getAllProducts() { 45 | return service.getAllProducts(); 46 | } 47 | 48 | /** 49 | * 获取仓库中指定的货物信息 50 | */ 51 | public Product getProduct(Integer id) { 52 | return service.getProduct(id); 53 | } 54 | 55 | /** 56 | * 创建或更新产品信息 57 | */ 58 | public Product saveProduct(Product product) { 59 | return service.saveProduct(product); 60 | } 61 | 62 | /** 63 | * 删除指定产品 64 | */ 65 | public void removeProduct(Integer id) { 66 | service.removeProduct(id); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/application/StockpileApplicationService.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.warehouse.application; 2 | 3 | import com.github.fenixsoft.bookstore.domain.warehouse.DeliveredStatus; 4 | import com.github.fenixsoft.bookstore.domain.warehouse.Stockpile; 5 | import com.github.fenixsoft.bookstore.warehouse.domain.StockpileService; 6 | 7 | import javax.inject.Inject; 8 | import javax.inject.Named; 9 | import javax.transaction.Transactional; 10 | 11 | /** 12 | * 商品库存的领域服务 13 | * 14 | * @author icyfenix@gmail.com 15 | * @date 2020/4/19 21:42 16 | **/ 17 | @Named 18 | @Transactional 19 | public class StockpileApplicationService { 20 | 21 | @Inject 22 | private StockpileService stockpileService; 23 | 24 | /** 25 | * 根据产品查询库存 26 | */ 27 | public Stockpile getStockpile(Integer productId) { 28 | return stockpileService.getByProductId(productId); 29 | } 30 | 31 | /** 32 | * 将指定的产品库存调整为指定数额 33 | */ 34 | public void setStockpileAmountByProductId(Integer productId, Integer amount) { 35 | stockpileService.set(productId, amount); 36 | } 37 | 38 | /** 39 | * 调整商品出库状态 40 | */ 41 | public void setDeliveredStatus(Integer productId, DeliveredStatus status, Integer amount) { 42 | switch (status) { 43 | case DECREASE: 44 | stockpileService.decrease(productId, amount); 45 | break; 46 | case INCREASE: 47 | stockpileService.increase(productId, amount); 48 | break; 49 | case FROZEN: 50 | stockpileService.frozen(productId, amount); 51 | break; 52 | case THAWED: 53 | stockpileService.thawed(productId, amount); 54 | break; 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/domain/Advertisement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse.domain; 20 | 21 | import com.github.fenixsoft.bookstore.domain.BaseEntity; 22 | 23 | import javax.persistence.Column; 24 | import javax.persistence.Entity; 25 | import javax.validation.constraints.NotEmpty; 26 | import javax.validation.constraints.NotNull; 27 | 28 | /** 29 | * 广告对象模型 30 | * 31 | * @author icyfenix@gmail.com 32 | * @date 2020/3/7 10:49 33 | **/ 34 | @Entity 35 | public class Advertisement extends BaseEntity { 36 | 37 | @NotEmpty(message = "广告图片不允许为空") 38 | private String image; 39 | 40 | @NotNull(message = "广告应当有关联的商品") 41 | @Column(name = "product_id") 42 | private Integer productId; 43 | 44 | public String getImage() { 45 | return image; 46 | } 47 | 48 | public void setImage(String image) { 49 | this.image = image; 50 | } 51 | 52 | public Integer getProductId() { 53 | return productId; 54 | } 55 | 56 | public void setProductId(Integer productId) { 57 | this.productId = productId; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/domain/AdvertisementRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse.domain; 20 | 21 | import org.springframework.dao.DataAccessException; 22 | import org.springframework.data.repository.CrudRepository; 23 | 24 | /** 25 | * 广告对象数据仓库 26 | * 27 | * @author icyfenix@gmail.com 28 | * @date 2020/3/7 10:51 29 | **/ 30 | public interface AdvertisementRepository extends CrudRepository { 31 | Iterable findAll() throws DataAccessException; 32 | } 33 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/domain/ProductRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse.domain; 20 | 21 | import com.github.fenixsoft.bookstore.domain.warehouse.Product; 22 | import org.springframework.data.repository.CrudRepository; 23 | 24 | import java.util.Collection; 25 | 26 | /** 27 | * 商品对象数据仓库 28 | * 29 | * @author icyfenix@gmail.com 30 | * @date 2020/3/6 20:56 31 | **/ 32 | public interface ProductRepository extends CrudRepository { 33 | 34 | Collection findByIdIn(Collection ids); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/domain/ProductService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse.domain; 20 | 21 | import com.github.fenixsoft.bookstore.domain.warehouse.Product; 22 | import com.github.fenixsoft.bookstore.dto.Item; 23 | import com.github.fenixsoft.bookstore.dto.Settlement; 24 | 25 | import javax.inject.Inject; 26 | import javax.inject.Named; 27 | import java.util.List; 28 | import java.util.function.Function; 29 | import java.util.stream.Collectors; 30 | 31 | /** 32 | * 产品领域服务 33 | * 34 | * @author icyfenix@gmail.com 35 | * @date 2020/3/12 20:58 36 | **/ 37 | @Named 38 | public class ProductService { 39 | 40 | @Inject 41 | private ProductRepository repository; 42 | 43 | /** 44 | * 根据结算单中货物的ID,填充货物的完整信息到结算单对象上 45 | */ 46 | public void replenishProductInformation(Settlement bill) { 47 | List ids = bill.getItems().stream().map(Item::getProductId).collect(Collectors.toList()); 48 | bill.productMap = repository.findByIdIn(ids).stream().collect(Collectors.toMap(Product::getId, Function.identity())); 49 | } 50 | 51 | /** 52 | * 获取仓库中所有的货物信息 53 | */ 54 | public Iterable getAllProducts() { 55 | return repository.findAll(); 56 | } 57 | 58 | /** 59 | * 获取仓库中指定的货物信息 60 | */ 61 | public Product getProduct(Integer id) { 62 | return repository.findById(id).orElse(null); 63 | } 64 | 65 | /** 66 | * 创建或者更新产品信息 67 | */ 68 | public Product saveProduct(Product product) { 69 | return repository.save(product); 70 | } 71 | 72 | /** 73 | * 删除指定产品 74 | */ 75 | public void removeProduct(Integer id) { 76 | repository.deleteById(id); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/domain/StockpileRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse.domain; 20 | 21 | import com.github.fenixsoft.bookstore.domain.warehouse.Stockpile; 22 | import org.springframework.data.repository.CrudRepository; 23 | 24 | /** 25 | * 库存数据仓库 26 | * 27 | * @author icyfenix@gmail.com 28 | * @date 2020/3/12 16:36 29 | **/ 30 | public interface StockpileRepository extends CrudRepository { 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/resource/AdvertisementResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.warehouse.resource; 20 | 21 | import com.github.fenixsoft.bookstore.warehouse.domain.Advertisement; 22 | import com.github.fenixsoft.bookstore.warehouse.domain.AdvertisementRepository; 23 | import org.springframework.cache.annotation.Cacheable; 24 | import org.springframework.stereotype.Component; 25 | 26 | import javax.inject.Inject; 27 | import javax.ws.rs.GET; 28 | import javax.ws.rs.Path; 29 | import javax.ws.rs.Produces; 30 | import javax.ws.rs.core.MediaType; 31 | 32 | /** 33 | * 广告相关的资源 34 | * 35 | * @author icyfenix@gmail.com 36 | * @date 2020/3/7 10:48 37 | **/ 38 | @Path("/advertisements") 39 | @Component 40 | @Produces(MediaType.APPLICATION_JSON) 41 | public class AdvertisementResource { 42 | 43 | @Inject 44 | AdvertisementRepository repository; 45 | 46 | @GET 47 | @Cacheable("resource.advertisements") 48 | public Iterable getAllAdvertisements() { 49 | return repository.findAll(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/java/com/github/fenixsoft/bookstore/warehouse/resource/StockpileResource.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.warehouse.resource; 2 | 3 | import com.github.fenixsoft.bookstore.domain.security.Role; 4 | import com.github.fenixsoft.bookstore.infrastructure.jaxrs.CommonResponse; 5 | import com.github.fenixsoft.bookstore.warehouse.application.StockpileApplicationService; 6 | import com.github.fenixsoft.bookstore.domain.warehouse.DeliveredStatus; 7 | import com.github.fenixsoft.bookstore.domain.warehouse.Stockpile; 8 | import org.springframework.cache.annotation.CacheConfig; 9 | import org.springframework.security.access.prepost.PreAuthorize; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.annotation.security.RolesAllowed; 13 | import javax.inject.Inject; 14 | import javax.ws.rs.*; 15 | import javax.ws.rs.core.MediaType; 16 | import javax.ws.rs.core.Response; 17 | 18 | /** 19 | * 库存相关的资源 20 | * 21 | * @author icyfenix@gmail.com 22 | * @date 2020/4/19 21:40 23 | **/ 24 | 25 | @Path("/products") 26 | @Component 27 | @CacheConfig(cacheNames = "resource.product") 28 | @Produces(MediaType.APPLICATION_JSON) 29 | public class StockpileResource { 30 | 31 | @Inject 32 | private StockpileApplicationService service; 33 | 34 | /** 35 | * 将指定的产品库存调整为指定数额 36 | */ 37 | @PATCH 38 | @Path("/stockpile/{productId}") 39 | @RolesAllowed(Role.ADMIN) 40 | @PreAuthorize("#oauth2.hasAnyScope('BROWSER')") 41 | public Response updateStockpile(@PathParam("productId") Integer productId, @QueryParam("amount") Integer amount) { 42 | return CommonResponse.op(() -> service.setStockpileAmountByProductId(productId, amount)); 43 | } 44 | 45 | /** 46 | * 根据产品查询库存 47 | */ 48 | @GET 49 | @Path("/stockpile/{productId}") 50 | @RolesAllowed(Role.ADMIN) 51 | @PreAuthorize("#oauth2.hasAnyScope('BROWSER','SERVICE')") 52 | public Stockpile queryStockpile(@PathParam("productId") Integer productId) { 53 | return service.getStockpile(productId); 54 | } 55 | 56 | // 以下是开放给内部微服务调用的方法 57 | 58 | /** 59 | * 将指定的产品库存调整为指定数额 60 | */ 61 | @PATCH 62 | @Path("/stockpile/delivered/{productId}") 63 | @PreAuthorize("#oauth2.hasAnyScope('SERVICE')") 64 | public Response setDeliveredStatus(@PathParam("productId") Integer productId, @QueryParam("status") DeliveredStatus status, @QueryParam("amount") Integer amount) { 65 | return CommonResponse.op(() -> service.setDeliveredStatus(productId, status, amount)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | enabled: false 4 | 5 | database: hsqldb 6 | 7 | spring: 8 | datasource: 9 | schema: "classpath:db/${database}/schema.sql" 10 | data: "classpath:db/${database}/data.sql" 11 | sql-script-encoding: UTF-8 12 | jpa: 13 | show-sql: false 14 | hibernate: 15 | ddl-auto: none 16 | open-in-view: false 17 | resources: 18 | chain: 19 | compressed: true 20 | cache: true 21 | cache: 22 | period: 86400 23 | 24 | logging: 25 | pattern: 26 | 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}" 27 | level: 28 | root: INFO 29 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ______ _ ____ __ _____ __ 2 | / ____/__ ____ (_) __ / __ )____ ____ / /_/ ___// /_____ ________ 3 | / /_ / _ \/ __ \/ / |/_/ / __ / __ \/ __ \/ __/\__ \/ __/ __ \/ ___/ _ \ 4 | / __/ / __/ / / / /> < / /_/ / /_/ / /_/ / /_ ___/ / /_/ /_/ / / / __/ 5 | /_/ \___/_/ /_/_/_/|_| /_____/\____/\____/\__//____/\__/\____/_/ \___/ 6 | Warehouse Domain 7 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: warehouse 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 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/resources/db/hsqldb/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE specification IF EXISTS; 2 | DROP TABLE advertisement IF EXISTS; 3 | DROP TABLE stockpile IF EXISTS; 4 | DROP TABLE product IF EXISTS; 5 | 6 | CREATE TABLE product 7 | ( 8 | id INTEGER IDENTITY PRIMARY KEY, 9 | title VARCHAR(50), 10 | price DECIMAL, 11 | rate FLOAT, 12 | description VARCHAR(8000), 13 | cover VARCHAR(100), 14 | detail VARCHAR(100) 15 | ); 16 | CREATE INDEX product_title ON product (title); 17 | 18 | CREATE TABLE stockpile 19 | ( 20 | id INTEGER IDENTITY PRIMARY KEY, 21 | amount INTEGER, 22 | frozen INTEGER, 23 | product_id INTEGER 24 | ); 25 | ALTER TABLE stockpile 26 | ADD CONSTRAINT fk_stockpile_product FOREIGN KEY (product_id) REFERENCES product (id) ON DELETE CASCADE; 27 | 28 | CREATE TABLE specification 29 | ( 30 | id INTEGER IDENTITY PRIMARY KEY, 31 | item VARCHAR(50), 32 | value VARCHAR(100), 33 | product_id INTEGER 34 | ); 35 | ALTER TABLE specification 36 | ADD CONSTRAINT fk_specification_product FOREIGN KEY (product_id) REFERENCES product (id) ON DELETE CASCADE; 37 | 38 | CREATE TABLE advertisement 39 | ( 40 | id INTEGER IDENTITY PRIMARY KEY, 41 | image VARCHAR(100), 42 | product_id INTEGER 43 | ); 44 | ALTER TABLE advertisement 45 | ADD CONSTRAINT fk_advertisement_product FOREIGN KEY (product_id) REFERENCES product (id) ON DELETE CASCADE; 46 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/resources/db/mysql/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS specification; 2 | DROP TABLE IF EXISTS advertisement; 3 | DROP TABLE IF EXISTS stockpile; 4 | DROP TABLE IF EXISTS product; 5 | 6 | CREATE TABLE IF NOT EXISTS product 7 | ( 8 | id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 9 | title VARCHAR(50), 10 | price DECIMAL, 11 | rate FLOAT, 12 | description VARCHAR(8000), 13 | cover VARCHAR(100), 14 | detail VARCHAR(100), 15 | INDEX (title) 16 | ) engine = InnoDB; 17 | 18 | CREATE TABLE IF NOT EXISTS stockpile 19 | ( 20 | id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 21 | amount INTEGER, 22 | frozen INTEGER, 23 | product_id INTEGER UNSIGNED, 24 | FOREIGN KEY (product_id) REFERENCES product (id) ON DELETE CASCADE 25 | ) engine = InnoDB; 26 | 27 | CREATE TABLE IF NOT EXISTS specification 28 | ( 29 | id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 30 | item VARCHAR(50), 31 | value VARCHAR(100), 32 | product_id INTEGER UNSIGNED, 33 | FOREIGN KEY (product_id) REFERENCES product (id) ON DELETE CASCADE 34 | ) engine = InnoDB; 35 | 36 | CREATE TABLE IF NOT EXISTS advertisement 37 | ( 38 | id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 39 | image VARCHAR(100), 40 | product_id INTEGER UNSIGNED, 41 | FOREIGN KEY (product_id) REFERENCES product (id) ON DELETE CASCADE 42 | ) engine = InnoDB; 43 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/resources/db/mysql/user.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS bookstore; 2 | 3 | ALTER DATABASE bookstore 4 | DEFAULT CHARACTER SET utf8 5 | DEFAULT COLLATE utf8_general_ci; 6 | 7 | GRANT ALL PRIVILEGES ON bookstore.* TO 'bookstore@%' IDENTIFIED BY 'bookstore'; 8 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/main/resources/public.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi+htQPOTvNMccJjOkCAz 3 | d3YlqBElURzkaeRLDoJYskyU59JdGO+p/q4JEH0DZOM2BbonGI4lIHFkiZLO4IBB 4 | Z5j2P7U6QYURt6+AyjS6RGw9v/wFdIRlyBI9D3EO7u8rCA4RktBLPavfEc5BwYX2 5 | Vb9wX6N63tV48cP1CoGU0GtIq9HTqbEQs5KVmme5n4XOuzxQ6B2AGaPBJgdq/K0Z 6 | WDkXiqPz6921X3oiNYPCQ22bvFxb4yFX8ZfbxeYc+1rN7PaUsK009qOx+qRenHpW 7 | gPVfagMbNYkm0TOHNOWXqukxE+soCDI/Nc++1khWCmQ9E2B82ap7IXsVBAnBIaV9 8 | WQIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/test/java/com/github/fenixsoft/bookstore/warehouse/AdvertisementResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.warehouse; 2 | 3 | import com.github.fenixsoft.bookstore.resource.JAXRSResourceBase; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author icyfenix@gmail.com 8 | * @date 2020/4/6 23:12 9 | **/ 10 | class AdvertisementResourceTest extends JAXRSResourceBase { 11 | 12 | @Test 13 | void getAllAdvertisements() { 14 | assertOK(get("/advertisements")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /bookstore-microservices-domain-warehouse/src/test/java/com/github/fenixsoft/bookstore/warehouse/ProductResourceTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.warehouse; 2 | 3 | import com.github.fenixsoft.bookstore.domain.warehouse.Product; 4 | import com.github.fenixsoft.bookstore.domain.warehouse.Stockpile; 5 | import com.github.fenixsoft.bookstore.resource.JAXRSResourceBase; 6 | import org.json.JSONException; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import javax.ws.rs.core.Response; 10 | 11 | import static org.junit.jupiter.api.Assertions.*; 12 | 13 | /** 14 | * @author icyfenix@gmail.com 15 | * @date 2020/4/21 17:40 16 | **/ 17 | class ProductResourceTest extends JAXRSResourceBase { 18 | 19 | @Test 20 | void getAllProducts() { 21 | assertOK(get("/products")); 22 | } 23 | 24 | @Test 25 | void getProduct() { 26 | assertOK(get("/products/1")); 27 | assertNoContent(get("/products/10086")); 28 | Product book = get("/products/1").readEntity(Product.class); 29 | assertEquals("深入理解Java虚拟机(第3版)", book.getTitle()); 30 | } 31 | 32 | @Test 33 | void updateProduct() { 34 | final Product book = get("/products/1").readEntity(Product.class); 35 | book.setTitle("深入理解Java虚拟机(第4版)"); 36 | assertForbidden(put("/products", book)); 37 | authenticatedScope(() -> assertOK(put("/products", book))); 38 | Product modifiedBook = get("/products/1").readEntity(Product.class); 39 | assertEquals("深入理解Java虚拟机(第4版)", modifiedBook.getTitle()); 40 | } 41 | 42 | @Test 43 | void createProduct() { 44 | final Product book = new Product(); 45 | book.setTitle("new book"); 46 | book.setPrice(50.0); 47 | book.setRate(8.0f); 48 | assertForbidden(post("/products", book)); 49 | authenticatedScope(() -> { 50 | Response response = post("/products", book); 51 | assertOK(response); 52 | Product fetchBook = response.readEntity(Product.class); 53 | assertEquals(book.getTitle(), fetchBook.getTitle()); 54 | assertNotNull(fetchBook.getId()); 55 | }); 56 | } 57 | 58 | @Test 59 | void removeProduct() throws JSONException { 60 | int number = jsonArray(get("/products")).length(); 61 | assertForbidden(delete("/products/1")); 62 | authenticatedScope(() -> assertOK(delete("/products/1"))); 63 | assertEquals(number - 1, jsonArray(get("/products")).length()); 64 | } 65 | 66 | @Test 67 | void updateAndQueryStockpile() { 68 | authenticatedScope(() -> { 69 | assertOK(patch("/products/stockpile/1?amount=20")); 70 | Stockpile stockpile = get("/products/stockpile/1").readEntity(Stockpile.class); 71 | assertEquals(20, stockpile.getAmount()); 72 | }); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/BaseEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain; 20 | 21 | import javax.persistence.GeneratedValue; 22 | import javax.persistence.GenerationType; 23 | import javax.persistence.Id; 24 | import javax.persistence.MappedSuperclass; 25 | import java.io.Serializable; 26 | 27 | /** 28 | * JavaBean领域对象的共同基类,定义了ID属性和其访问字段 29 | * 30 | * @author icyfenix@gmail.com 31 | * @date 2020/3/6 10:52 32 | **/ 33 | @MappedSuperclass 34 | public class BaseEntity implements Serializable { 35 | 36 | @Id 37 | @GeneratedValue(strategy = GenerationType.IDENTITY) 38 | private Integer id; 39 | 40 | public Integer getId() { 41 | return id; 42 | } 43 | 44 | public void setId(Integer id) { 45 | this.id = id; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/account/Account.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.account; 20 | 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | import com.github.fenixsoft.bookstore.domain.BaseEntity; 23 | 24 | import javax.persistence.Column; 25 | import javax.persistence.Entity; 26 | import javax.validation.constraints.Email; 27 | import javax.validation.constraints.NotEmpty; 28 | import javax.validation.constraints.Pattern; 29 | 30 | /** 31 | * 用户实体 32 | * 33 | * @author icyfenix@gmail.com 34 | * @date 2020/3/6 23:08 35 | */ 36 | @Entity 37 | public class Account extends BaseEntity { 38 | 39 | @NotEmpty(message = "用户不允许为空") 40 | private String username; 41 | 42 | // 密码字段不参与序列化(但反序列化是参与的)、不参与更新(但插入是参与的) 43 | // 这意味着密码字段不会在获取对象(很多操作都会关联用户对象)的时候泄漏出去; 44 | // 也意味着此时“修改密码”一类的功能无法以用户对象资源的接口来处理(因为更新对象时密码不会被更新),需要单独提供接口去完成 45 | // @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) 46 | // @Column(updatable = false) 47 | private String password; 48 | 49 | @NotEmpty(message = "用户姓名不允许为空") 50 | private String name; 51 | 52 | private String avatar; 53 | 54 | @Pattern(regexp = "1\\d{10}", message = "手机号格式不正确") 55 | private String telephone; 56 | 57 | @Email(message = "邮箱格式不正确") 58 | private String email; 59 | 60 | private String location; 61 | 62 | public String getUsername() { 63 | return username; 64 | } 65 | 66 | public void setUsername(String username) { 67 | this.username = username; 68 | } 69 | 70 | public String getPassword() { 71 | return password; 72 | } 73 | 74 | public void setPassword(String password) { 75 | this.password = password; 76 | } 77 | 78 | public String getName() { 79 | return name; 80 | } 81 | 82 | public void setName(String name) { 83 | this.name = name; 84 | } 85 | 86 | public String getAvatar() { 87 | return avatar; 88 | } 89 | 90 | public void setAvatar(String avatar) { 91 | this.avatar = avatar; 92 | } 93 | 94 | public String getTelephone() { 95 | return telephone; 96 | } 97 | 98 | public void setTelephone(String telephone) { 99 | this.telephone = telephone; 100 | } 101 | 102 | public String getEmail() { 103 | return email; 104 | } 105 | 106 | public void setEmail(String email) { 107 | this.email = email; 108 | } 109 | 110 | public String getLocation() { 111 | return location; 112 | } 113 | 114 | public void setLocation(String location) { 115 | this.location = location; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/security/AccountServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.domain.security; 2 | 3 | import com.github.fenixsoft.bookstore.domain.account.Account; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | 6 | import javax.ws.rs.Consumes; 7 | import javax.ws.rs.GET; 8 | import javax.ws.rs.Path; 9 | import javax.ws.rs.PathParam; 10 | import javax.ws.rs.core.MediaType; 11 | 12 | /** 13 | * 用户信息的远程服务客户端 14 | * 各个工程都可能涉及取当前用户之类的操作,将此客户端放到基础包以便通用 15 | * 16 | * @author icyfenix@gmail.com 17 | * @date 2020/4/18 12:33 18 | **/ 19 | @FeignClient(name = "account") 20 | public interface AccountServiceClient { 21 | 22 | @GET 23 | @Path("/restful/accounts/{username}") 24 | @Consumes(MediaType.APPLICATION_JSON) 25 | Account findByUsername(@PathParam("username") String username); 26 | } 27 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/security/AuthenticAccount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.security; 20 | 21 | 22 | import com.github.fenixsoft.bookstore.domain.account.Account; 23 | import org.springframework.beans.BeanUtils; 24 | import org.springframework.security.core.GrantedAuthority; 25 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 26 | import org.springframework.security.core.userdetails.UserDetails; 27 | 28 | import java.util.Collection; 29 | import java.util.HashSet; 30 | 31 | /** 32 | * 认证用户模型 33 | *

34 | * 用户注册之后,包含其业务属性,如姓名、电话、地址,用于业务发生,存储于Account对象中 35 | * 也包含其用于认证的属性,譬如密码、角色、是否停用,存储于AuthenticAccount对象中 36 | * 37 | * @author icyfenix@gmail.com 38 | * @date 2020/3/7 20:46 39 | **/ 40 | public class AuthenticAccount extends Account implements UserDetails { 41 | 42 | public AuthenticAccount() { 43 | super(); 44 | authorities.add(new SimpleGrantedAuthority(Role.USER)); 45 | } 46 | 47 | public AuthenticAccount(Account origin) { 48 | this(); 49 | BeanUtils.copyProperties(origin, this); 50 | if (getId() == 1) { 51 | // 由于没有做用户管理功能,默认给系统中第一个用户赋予管理员角色 52 | authorities.add(new SimpleGrantedAuthority(Role.ADMIN)); 53 | } 54 | } 55 | 56 | /** 57 | * 该用户拥有的授权,譬如读取权限、修改权限、增加权限等等 58 | */ 59 | private Collection authorities = new HashSet<>(); 60 | 61 | @Override 62 | public Collection getAuthorities() { 63 | return authorities; 64 | } 65 | 66 | public void setAuthorities(Collection authorities) { 67 | this.authorities = authorities; 68 | } 69 | 70 | /** 71 | * 账号是否过期 72 | */ 73 | @Override 74 | public boolean isAccountNonExpired() { 75 | return true; 76 | } 77 | 78 | /** 79 | * 是否锁定 80 | */ 81 | @Override 82 | public boolean isAccountNonLocked() { 83 | return true; 84 | } 85 | 86 | /** 87 | * 密码是否过期 88 | */ 89 | @Override 90 | public boolean isCredentialsNonExpired() { 91 | return true; 92 | } 93 | 94 | /** 95 | * 是否被锁定 96 | */ 97 | @Override 98 | public boolean isEnabled() { 99 | return true; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/security/AuthenticAccountDetailsService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.security; 20 | 21 | import org.springframework.security.core.userdetails.UserDetails; 22 | import org.springframework.security.core.userdetails.UserDetailsService; 23 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 24 | 25 | import javax.inject.Inject; 26 | import javax.inject.Named; 27 | import java.util.Optional; 28 | 29 | /** 30 | * 认证用户信息查询服务 31 | *

32 | * {@link UserDetailsService}接口定义了从外部(数据库、LDAP,任何地方)根据用户名查询到 33 | */ 34 | @Named 35 | public class AuthenticAccountDetailsService implements UserDetailsService { 36 | 37 | @Inject 38 | private AuthenticAccountRepository accountRepository; 39 | 40 | /** 41 | * 根据用户名查询用户角色、权限等信息 42 | * 如果用户名无法查询到对应的用户,或者权限不满足,请直接抛出{@link UsernameNotFoundException},勿返回null 43 | */ 44 | @Override 45 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 46 | return Optional.ofNullable(accountRepository.findByUsername(username)).orElseThrow(() -> new UsernameNotFoundException("未找到该用户:" + username)); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/security/AuthenticAccountRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.security; 20 | 21 | import com.github.fenixsoft.bookstore.domain.account.Account; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.stereotype.Component; 24 | 25 | /** 26 | * 认证用户的数据仓库 27 | * 28 | * @author icyfenix@gmail.com 29 | * @date 2020/3/8 15:21 30 | **/ 31 | @Component 32 | public class AuthenticAccountRepository { 33 | @Autowired 34 | private AccountServiceClient userService; 35 | 36 | public AuthenticAccount findByUsername(String username) { 37 | Account account = userService.findByUsername(username); 38 | return new AuthenticAccount(account); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/security/GrantType.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.domain.security; 2 | 3 | /** 4 | * OAuth2 授权类型 5 | * 6 | * @author icyfenix@gmail.com 7 | * @date 2020/4/19 19:36 8 | **/ 9 | public interface GrantType { 10 | 11 | // 四种标准类型 12 | String PASSWORD = "password"; 13 | String CLIENT_CREDENTIALS = "client_credentials"; 14 | String IMPLICIT = "implicit"; 15 | String AUTHORIZATIONCODE = "authorizationcode"; 16 | // 用于刷新令牌 17 | String REFRESH_TOKEN = "refresh_token"; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/security/Role.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.security; 20 | 21 | /** 22 | * 角色常量类 23 | * 目前系统中只有2种角色:用户,管理员 24 | * 为了注解{@link javax.annotation.security.RolesAllowed}中使用方便,定义为字符串常量(非枚举) 25 | * 26 | * @author icyfenix@gmail.com 27 | * @date 2020/3/16 11:32 28 | **/ 29 | public interface Role { 30 | String USER = "ROLE_USER"; 31 | String ADMIN = "ROLE_ADMIN"; 32 | } 33 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/security/Scope.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.domain.security; 2 | 3 | /** 4 | * 访问范围常量类 5 | *

6 | * 目前有“来自浏览器的访问”和“来自微服务的访问”两个常量 7 | * 8 | * @author icyfenix@gmail.com 9 | * @date 2020/4/19 18:24 10 | **/ 11 | public interface Scope { 12 | 13 | String BROWSER = "BROWSER"; 14 | 15 | String SERVICE = "SERVICE"; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/warehouse/DeliveredStatus.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.domain.warehouse; 2 | 3 | /** 4 | * 待交付商品的状态 5 | * 6 | * @author icyfenix@gmail.com 7 | * @date 2020/4/20 9:52 8 | **/ 9 | public enum DeliveredStatus { 10 | 11 | /** 12 | * 出库调减库存 13 | */ 14 | DECREASE, 15 | 16 | /** 17 | * 入库调增库存 18 | */ 19 | INCREASE, 20 | 21 | /** 22 | * 待出库冻结库存 23 | */ 24 | FROZEN, 25 | 26 | /** 27 | * 取消出库解冻库存 28 | */ 29 | THAWED; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/warehouse/Product.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.warehouse; 20 | 21 | import com.github.fenixsoft.bookstore.domain.BaseEntity; 22 | 23 | import javax.persistence.*; 24 | import javax.validation.constraints.Max; 25 | import javax.validation.constraints.Min; 26 | import javax.validation.constraints.NotEmpty; 27 | import javax.validation.constraints.NotNull; 28 | import java.util.Set; 29 | 30 | /** 31 | * 商品对象模型 32 | * 33 | * @author icyfenix@gmail.com 34 | * @date 2020/3/6 10:43 35 | */ 36 | @Entity 37 | public class Product extends BaseEntity { 38 | 39 | @NotEmpty(message = "商品名称不允许为空") 40 | private String title; 41 | 42 | @NotNull(message = "商品应当有明确的价格") 43 | @Min(value = 0, message = "商品价格最低为零") 44 | // 这里是偷懒,正式场合使用BigDecimal来表示金额 45 | private Double price; 46 | 47 | @Min(value = 0, message = "评分最低为0") 48 | @Max(value = 10, message = "评分最高为10") 49 | private Float rate; 50 | 51 | private String description; 52 | 53 | private String cover; 54 | 55 | private String detail; 56 | 57 | @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 58 | @JoinColumn(name = "product_id") 59 | private Set specifications; 60 | 61 | public String getTitle() { 62 | return title; 63 | } 64 | 65 | public void setTitle(String title) { 66 | this.title = title; 67 | } 68 | 69 | public Double getPrice() { 70 | return price; 71 | } 72 | 73 | public void setPrice(Double price) { 74 | this.price = price; 75 | } 76 | 77 | public Float getRate() { 78 | return rate; 79 | } 80 | 81 | public void setRate(Float rate) { 82 | this.rate = rate; 83 | } 84 | 85 | public String getDescription() { 86 | return description; 87 | } 88 | 89 | public void setDescription(String description) { 90 | this.description = description; 91 | } 92 | 93 | public String getCover() { 94 | return cover; 95 | } 96 | 97 | public void setCover(String cover) { 98 | this.cover = cover; 99 | } 100 | 101 | public String getDetail() { 102 | return detail; 103 | } 104 | 105 | public void setDetail(String detail) { 106 | this.detail = detail; 107 | } 108 | 109 | public Set getSpecifications() { 110 | return specifications; 111 | } 112 | 113 | public void setSpecifications(Set specifications) { 114 | this.specifications = specifications; 115 | } 116 | 117 | 118 | } 119 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/warehouse/Specification.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.warehouse; 20 | 21 | import com.github.fenixsoft.bookstore.domain.BaseEntity; 22 | 23 | import javax.persistence.Column; 24 | import javax.persistence.Entity; 25 | import javax.validation.constraints.NotEmpty; 26 | import javax.validation.constraints.NotNull; 27 | 28 | /** 29 | * 商品规格 30 | * 31 | * @author icyfenix@gmail.com 32 | * @date 2020/3/6 19:33 33 | **/ 34 | @Entity 35 | public class Specification extends BaseEntity { 36 | 37 | @NotEmpty(message = "商品规格名称不允许为空") 38 | private String item; 39 | 40 | @NotEmpty(message = "商品规格内容不允许为空") 41 | private String value; 42 | 43 | @NotNull(message = "商品规格必须归属于指定商品") 44 | @Column(name = "product_id") 45 | private Integer productId; 46 | 47 | public String getItem() { 48 | return item; 49 | } 50 | 51 | public void setItem(String item) { 52 | this.item = item; 53 | } 54 | 55 | public String getValue() { 56 | return value; 57 | } 58 | 59 | public void setValue(String value) { 60 | this.value = value; 61 | } 62 | 63 | public Integer getProductId() { 64 | return productId; 65 | } 66 | 67 | public void setProductId(Integer productId) { 68 | this.productId = productId; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/domain/warehouse/Stockpile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.domain.warehouse; 20 | 21 | import com.github.fenixsoft.bookstore.domain.BaseEntity; 22 | 23 | import javax.persistence.Entity; 24 | import javax.persistence.FetchType; 25 | import javax.persistence.JoinColumn; 26 | import javax.persistence.OneToOne; 27 | 28 | /** 29 | * 商品库存 30 | * 31 | * @author icyfenix@gmail.com 32 | * @date 2020/3/12 16:34 33 | **/ 34 | @Entity 35 | public class Stockpile extends BaseEntity { 36 | 37 | private Integer amount; 38 | 39 | private Integer frozen; 40 | 41 | @OneToOne(fetch = FetchType.LAZY) 42 | @JoinColumn(name = "product_id") 43 | private transient Product product; 44 | 45 | public Integer getAmount() { 46 | return amount; 47 | } 48 | 49 | public void setAmount(Integer amount) { 50 | this.amount = amount; 51 | } 52 | 53 | public Integer getFrozen() { 54 | return frozen; 55 | } 56 | 57 | public void frozen(Integer number) { 58 | this.amount -= number; 59 | this.frozen += number; 60 | } 61 | 62 | public void thawed(Integer number) { 63 | frozen(-1 * number); 64 | } 65 | 66 | public void decrease(Integer number) { 67 | this.frozen -= number; 68 | } 69 | 70 | public void increase(Integer number) { 71 | this.frozen += number; 72 | } 73 | 74 | public Product getProduct() { 75 | return product; 76 | } 77 | 78 | public void setProduct(Product product) { 79 | this.product = product; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/dto/Item.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.dto; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import javax.validation.constraints.Min; 6 | import javax.validation.constraints.NotNull; 7 | 8 | /** 9 | * 结算单中要购买的商品 10 | * 11 | * @author icyfenix@gmail.com 12 | * @date 2020/4/19 22:16 13 | **/ 14 | public class Item { 15 | 16 | @NotNull(message = "结算单中必须有明确的商品数量") 17 | @Min(value = 1, message = "结算单中商品数量至少为一件") 18 | private Integer amount; 19 | 20 | @JsonProperty("id") 21 | @NotNull(message = "结算单中必须有明确的商品信息") 22 | private Integer productId; 23 | 24 | public Integer getAmount() { 25 | return amount; 26 | } 27 | 28 | public void setAmount(Integer amount) { 29 | this.amount = amount; 30 | } 31 | 32 | public Integer getProductId() { 33 | return productId; 34 | } 35 | 36 | public void setProductId(Integer productId) { 37 | this.productId = productId; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/dto/Purchase.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.dto; 2 | 3 | import javax.validation.constraints.NotEmpty; 4 | 5 | /** 6 | * 结算单中的配送信息 7 | * 8 | * @author icyfenix@gmail.com 9 | * @date 2020/4/19 22:15 10 | **/ 11 | public class Purchase { 12 | 13 | private Boolean delivery = true; 14 | 15 | @NotEmpty(message = "配送信息中缺少支付方式") 16 | private String pay; 17 | 18 | @NotEmpty(message = "配送信息中缺少收件人姓名") 19 | private String name; 20 | 21 | @NotEmpty(message = "配送信息中缺少收件人电话") 22 | private String telephone; 23 | 24 | @NotEmpty(message = "配送信息中缺少收件地址") 25 | private String location; 26 | 27 | public Boolean getDelivery() { 28 | return delivery; 29 | } 30 | 31 | public void setDelivery(Boolean delivery) { 32 | this.delivery = delivery; 33 | } 34 | 35 | public String getPay() { 36 | return pay; 37 | } 38 | 39 | public void setPay(String pay) { 40 | this.pay = pay; 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public void setName(String name) { 48 | this.name = name; 49 | } 50 | 51 | public String getTelephone() { 52 | return telephone; 53 | } 54 | 55 | public void setTelephone(String telephone) { 56 | this.telephone = telephone; 57 | } 58 | 59 | public String getLocation() { 60 | return location; 61 | } 62 | 63 | public void setLocation(String location) { 64 | this.location = location; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/dto/Settlement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.dto; 20 | 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | import com.github.fenixsoft.bookstore.domain.warehouse.Product; 23 | 24 | import javax.validation.constraints.Min; 25 | import javax.validation.constraints.NotEmpty; 26 | import javax.validation.constraints.NotNull; 27 | import javax.validation.constraints.Size; 28 | import java.util.Collection; 29 | import java.util.Map; 30 | 31 | /** 32 | * 支付结算单模型 33 | * 34 | * @author icyfenix@gmail.com 35 | * @date 2020/3/12 11:35 36 | **/ 37 | public class Settlement { 38 | 39 | @Size(min = 1, message = "结算单中缺少商品清单") 40 | private Collection items; 41 | 42 | @NotNull(message = "结算单中缺少配送信息") 43 | private Purchase purchase; 44 | 45 | /** 46 | * 购物清单中的商品信息 47 | * 基于安全原因(避免篡改价格),改信息不会取客户端的,需在服务端根据商品ID再查询出来 48 | */ 49 | public transient Map productMap; 50 | 51 | public Collection getItems() { 52 | return items; 53 | } 54 | 55 | public void setItems(Collection items) { 56 | this.items = items; 57 | } 58 | 59 | public Purchase getPurchase() { 60 | return purchase; 61 | } 62 | 63 | public void setPurchase(Purchase purchase) { 64 | this.purchase = purchase; 65 | } 66 | 67 | 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/cache/CacheConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.infrastructure.cache; 2 | 3 | import com.github.benmanes.caffeine.cache.Caffeine; 4 | import org.springframework.cache.Cache; 5 | import org.springframework.cache.CacheManager; 6 | import org.springframework.cache.caffeine.CaffeineCache; 7 | import org.springframework.cache.caffeine.CaffeineCacheManager; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * 为系统提供一些代码上使用的缓存 15 | * 16 | * @author icyfenix@gmail.com 17 | * @date 2020/4/7 17:38 18 | **/ 19 | @Configuration 20 | public class CacheConfiguration { 21 | 22 | /** 23 | * 系统默认缓存TTL时间:4分钟 24 | * 一些需要用到缓存的数据,譬如支付单,需要按此数据来规划过期时间 25 | */ 26 | public static final long SYSTEM_DEFAULT_EXPIRES = 4 * 60 * 1000; 27 | 28 | @Bean 29 | public CacheManager configCacheManager() { 30 | CaffeineCacheManager manager = new CaffeineCacheManager(); 31 | manager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(SYSTEM_DEFAULT_EXPIRES, TimeUnit.MILLISECONDS)); 32 | return manager; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/configuration/FeignConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.infrastructure.configuration; 2 | 3 | import feign.Contract; 4 | import feign.RequestInterceptor; 5 | import feign.jaxrs2.JAXRS2Contract; 6 | import org.springframework.cloud.openfeign.EnableFeignClients; 7 | import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Profile; 11 | import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; 12 | import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; 13 | 14 | import javax.inject.Inject; 15 | 16 | /** 17 | * 启动FeignClient扫描,并配置: 18 | * 1. 并指定包包扫描地址 19 | * 2. 设置交互为JAX-RS2方式,实际Feign中的JAX-RS2指的是1.1 20 | * 3. 在请求时自动加入基于OAuth2的客户端模式认证的Header 21 | * 22 | * @author icyfenix@gmail.com 23 | * @date 2020/4/18 22:38 24 | **/ 25 | @Configuration 26 | @Profile("!test") 27 | @EnableFeignClients(basePackages = {"com.github.fenixsoft.bookstore"}) 28 | public class FeignConfiguration { 29 | 30 | @Inject 31 | private ClientCredentialsResourceDetails resource; 32 | 33 | @Bean 34 | public Contract feignContract() { 35 | return new JAXRS2Contract(); 36 | } 37 | 38 | @Bean 39 | public RequestInterceptor oauth2FeignRequestInterceptor() { 40 | return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), resource); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/configuration/JPAConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.infrastructure.configuration; 2 | 3 | import org.springframework.boot.autoconfigure.domain.EntityScan; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * 配置JPA EntityManager的搜索范围 8 | * 避免各个工程由于Application文件在此包名的下级而导致基础包中的Entity搜索不到 9 | * 10 | * @author icyfenix@gmail.com 11 | * @date 2020/4/18 15:03 12 | **/ 13 | @Configuration 14 | @EntityScan(basePackages = {"com.github.fenixsoft.bookstore"}) 15 | public class JPAConfiguration { 16 | } 17 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/configuration/JerseyConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.infrastructure.configuration; 20 | 21 | import org.glassfish.jersey.server.ResourceConfig; 22 | import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; 23 | import org.springframework.context.annotation.Configuration; 24 | import org.springframework.core.type.filter.AnnotationTypeFilter; 25 | import org.springframework.util.ClassUtils; 26 | 27 | import javax.ws.rs.ApplicationPath; 28 | import javax.ws.rs.Path; 29 | import javax.ws.rs.ext.Provider; 30 | import java.util.Objects; 31 | import java.util.stream.Collectors; 32 | 33 | /** 34 | * Jersey服务器配置 35 | *

36 | * 使用Jersey来提供对JAX-RS(JSR 370:Java API for Restful Web Services)的支持 37 | * 这里设置了所有服务的前缀路径“restful”和restful服务资源的包路径 38 | * 39 | * @author icyfenix@gmail.com 40 | * @date 2020/3/6 21:10 41 | **/ 42 | @Configuration 43 | @ApplicationPath("/restful") 44 | public class JerseyConfiguration extends ResourceConfig { 45 | public JerseyConfiguration() { 46 | scanPackages("com.github.fenixsoft.bookstore"); 47 | } 48 | 49 | /** 50 | * Jersey的packages()方法在Jar形式运行下有问题,这里修理一下 51 | */ 52 | private void scanPackages(String scanPackage) { 53 | ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); 54 | scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class)); 55 | scanner.addIncludeFilter(new AnnotationTypeFilter(Provider.class)); 56 | this.registerClasses(scanner.findCandidateComponents(scanPackage).stream() 57 | .map(beanDefinition -> ClassUtils.resolveClassName(Objects.requireNonNull(beanDefinition.getBeanClassName()), this.getClassLoader())) 58 | .collect(Collectors.toSet())); 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/jaxrs/AccessDeniedExceptionMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.infrastructure.jaxrs; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.security.access.AccessDeniedException; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.ws.rs.core.Context; 9 | import javax.ws.rs.core.Response; 10 | import javax.ws.rs.ext.ExceptionMapper; 11 | import javax.ws.rs.ext.Provider; 12 | 13 | /** 14 | * 用于统一处理在Resource中由于Spring Security授权访问产生的异常信息 15 | * 16 | * @author icyfenix@gmail.com 17 | * @date 2020/4/7 0:09 18 | **/ 19 | @Provider 20 | public class AccessDeniedExceptionMapper implements ExceptionMapper { 21 | 22 | private static final Logger log = LoggerFactory.getLogger(AccessDeniedExceptionMapper.class); 23 | 24 | @Context 25 | private HttpServletRequest request; 26 | 27 | @Override 28 | public Response toResponse(AccessDeniedException exception) { 29 | log.warn("越权访问被禁止 {}: {}", request.getMethod(), request.getPathInfo()); 30 | return CommonResponse.send(Response.Status.FORBIDDEN, exception.getMessage()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/jaxrs/BaseExceptionMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.infrastructure.jaxrs; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import javax.ws.rs.core.Response; 25 | import javax.ws.rs.ext.ExceptionMapper; 26 | import javax.ws.rs.ext.Provider; 27 | 28 | /** 29 | * 用于兜底的全局处理器,如果其他所有的Mapper都不合适,将由此处理把错误带到前端 30 | * 31 | * @author icyfenix@gmail.c 32 | * @date 2020/3/12 16:43 33 | **/ 34 | @Provider 35 | public class BaseExceptionMapper implements ExceptionMapper { 36 | 37 | private static final Logger log = LoggerFactory.getLogger(BaseExceptionMapper.class); 38 | 39 | @Override 40 | public Response toResponse(Throwable exception) { 41 | log.error(exception.getMessage(), exception); 42 | return CommonResponse.failure(exception.getMessage()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/jaxrs/CodedMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.infrastructure.jaxrs; 20 | 21 | import com.fasterxml.jackson.annotation.JsonInclude; 22 | 23 | /** 24 | * 带编码的实体容器 25 | *

26 | * 一般来说REST服务应采用HTTP Status Code带回错误信息编码 27 | * 但很多前端开发都习惯以JSON-RPC的风格处理异常,所以仍然保留这个编码容器 28 | * 用于返回给客户端以形式为“{code,message,data}”的对象格式 29 | * 30 | * @author icyfenix@gmail.com 31 | * @date 2020/3/6 15:34 32 | */ 33 | @JsonInclude(JsonInclude.Include.NON_NULL) 34 | public class CodedMessage { 35 | /** 36 | * 约定的成功标志 37 | */ 38 | public static final Integer CODE_SUCCESS = 0; 39 | /** 40 | * 默认的失败标志,其他失败含义可以自定义 41 | */ 42 | public static final Integer CODE_DEFAULT_FAILURE = 1; 43 | 44 | private Integer code; 45 | private String message; 46 | private Object data; 47 | 48 | public CodedMessage(Integer code, String message) { 49 | setCode(code); 50 | setMessage(message); 51 | } 52 | 53 | public Integer getCode() { 54 | return code; 55 | } 56 | 57 | public void setCode(Integer code) { 58 | this.code = code; 59 | } 60 | 61 | public String getMessage() { 62 | return message; 63 | } 64 | 65 | public void setMessage(String message) { 66 | this.message = message; 67 | } 68 | 69 | public Object getData() { 70 | return data; 71 | } 72 | 73 | public void setData(Object data) { 74 | this.data = data; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/jaxrs/CommonResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.infrastructure.jaxrs; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import javax.ws.rs.core.MediaType; 25 | import javax.ws.rs.core.Response; 26 | import java.util.function.Consumer; 27 | 28 | /** 29 | * 为了简化编码而设计的HTTP Response对象包装类和工具集 30 | *

31 | * 带有服务状态编码的(带有Code字段的)JavaBean领域对象包装类 32 | * Code字段的通常用于服务消费者判定该请求的业务处理是否成功。 33 | *

34 | * 统一约定: 35 | * - 当服务调用正常完成,返回Code一律以0表示 36 | * - 当服务调用产生异常,可自定义不为0的Code值,此时Message字段作为返回客户端的详细信息 37 | * 38 | * @author icyfenix@gmail.com 39 | * @date 2020/3/6 15:46 40 | **/ 41 | public abstract class CommonResponse { 42 | 43 | private static final Logger log = LoggerFactory.getLogger(CommonResponse.class); 44 | 45 | /** 46 | * 向客户端发送自定义操作信息 47 | */ 48 | public static Response send(Response.Status status, String message) { 49 | Integer code = status.getFamily() == Response.Status.Family.SUCCESSFUL ? CodedMessage.CODE_SUCCESS : CodedMessage.CODE_DEFAULT_FAILURE; 50 | return Response.status(status).type(MediaType.APPLICATION_JSON).entity(new CodedMessage(code, message)).build(); 51 | } 52 | 53 | /** 54 | * 向客户端发送操作失败的信息 55 | */ 56 | public static Response failure(String message) { 57 | return send(Response.Status.INTERNAL_SERVER_ERROR, message); 58 | } 59 | 60 | /** 61 | * 向客户端发送操作成功的信息 62 | */ 63 | public static Response success(String message) { 64 | return send(Response.Status.OK, message); 65 | } 66 | 67 | /** 68 | * 向客户端发送操作成功的信息 69 | */ 70 | public static Response success() { 71 | return send(Response.Status.OK, "操作已成功"); 72 | } 73 | 74 | /** 75 | * 执行操作,并根据操作是否成功返回给客户端相应信息 76 | * 封装了在服务端接口中很常见的执行操作,成功返回成功标志、失败返回失败标志的通用操作,用于简化编码 77 | */ 78 | public static Response op(Runnable executor) { 79 | return op(executor, e -> log.error(e.getMessage(), e)); 80 | } 81 | 82 | /** 83 | * 执行操作(带自定义的失败处理),并根据操作是否成功返回给客户端相应信息 84 | * 封装了在服务端接口中很常见的执行操作,成功返回成功标志、失败返回失败标志的通用操作,用于简化编码 85 | */ 86 | public static Response op(Runnable executor, Consumer exceptionConsumer) { 87 | try { 88 | executor.run(); 89 | return CommonResponse.success(); 90 | } catch (Exception e) { 91 | exceptionConsumer.accept(e); 92 | return CommonResponse.failure(e.getMessage()); 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/jaxrs/ViolationExceptionMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.infrastructure.jaxrs; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import javax.validation.ConstraintViolation; 25 | import javax.validation.ConstraintViolationException; 26 | import javax.ws.rs.core.Response; 27 | import javax.ws.rs.ext.ExceptionMapper; 28 | import javax.ws.rs.ext.Provider; 29 | import java.util.stream.Collectors; 30 | 31 | /** 32 | * 用于统一处理在Resource中由于验证器验证失败而带回客户端的错误信息 33 | * 34 | * @author icyfenix@gmail.com 35 | * @date 2020/3/10 23:37 36 | **/ 37 | @Provider 38 | public class ViolationExceptionMapper implements ExceptionMapper { 39 | 40 | private static final Logger log = LoggerFactory.getLogger(ViolationExceptionMapper.class); 41 | 42 | @Override 43 | public Response toResponse(ConstraintViolationException exception) { 44 | log.warn("客户端传入了校验结果为非法的数据", exception); 45 | String msg = exception.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";")); 46 | return CommonResponse.send(Response.Status.BAD_REQUEST, msg); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/security/HS256JWTAccessToken.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.infrastructure.security; 2 | 3 | import org.springframework.security.core.userdetails.UserDetailsService; 4 | 5 | import javax.inject.Named; 6 | 7 | /** 8 | * 基于HMAC-SHA256的JWT令牌实现 9 | *

10 | * 并不推荐在微服务环境中使用这种必须中心化验证的令牌,所以这里的@Named是被注释的。 11 | * 保留该实现主要是为了与单体版本中的HS265实现保持一致,便于与RSA256/ECDSA256等实现进行对比。 12 | * 13 | * @author icyfenix@gmail.com 14 | * @date 2020/7/17 17:34 15 | **/ 16 | // @Named 17 | public class HS256JWTAccessToken extends JWTAccessToken { 18 | 19 | // 签名私钥 20 | // 此处内容是我随便写的UUID,按照JWT约定默认是256Bit的,其实任何格式都可以,只是要注意保密,不要公开出去 21 | private static final String JWT_TOKEN_SIGNING_PRIVATE_KEY = "601304E0-8AD4-40B0-BD51-0B432DC47461"; 22 | 23 | public HS256JWTAccessToken(UserDetailsService userDetailsService) { 24 | super(userDetailsService); 25 | // 设置签名私钥 26 | setSigningKey(JWT_TOKEN_SIGNING_PRIVATE_KEY); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/security/JWTAccessTokenService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.infrastructure.security; 20 | 21 | import org.springframework.security.authentication.AuthenticationManager; 22 | import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager; 23 | import org.springframework.security.oauth2.provider.token.DefaultTokenServices; 24 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 25 | 26 | import javax.inject.Inject; 27 | import javax.inject.Named; 28 | import java.util.Optional; 29 | 30 | /** 31 | * JWT访问令牌服务 32 | *

33 | * 在此服务中提供了令牌如何存储、携带哪些信息、如何签名、持续多长时间等相关内容的定义 34 | * 令牌服务应当会被授权服务器注册验证Endpoint时候调用到 35 | * 36 | * @author icyfenix@gmail.com 37 | * @date 2020/3/8 11:07 38 | **/ 39 | @Named 40 | public class JWTAccessTokenService extends DefaultTokenServices { 41 | 42 | /** 43 | * 构建JWT令牌,并进行默认的配置 44 | */ 45 | @Inject 46 | public JWTAccessTokenService(JWTAccessToken token, 47 | OAuthClientDetailsService clientService, 48 | Optional authenticationManager) { 49 | // 设置令牌的持久化容器 50 | // 令牌持久化有多种方式,单节点服务可以存放在Session中,集群可以存放在Redis中 51 | // 而JWT是后端无状态、前端存储的解决方案,Token的存储由前端完成 52 | setTokenStore(new JwtTokenStore(token)); 53 | // 令牌支持的客户端详情 54 | setClientDetailsService(clientService); 55 | // 设置验证管理器,在鉴权的时候需要用到 56 | setAuthenticationManager(authenticationManager.orElseGet(() -> { 57 | OAuth2AuthenticationManager manager = new OAuth2AuthenticationManager(); 58 | manager.setClientDetailsService(clientService); 59 | manager.setTokenServices(this); 60 | return manager; 61 | })); 62 | // 定义令牌的额外负载 63 | setTokenEnhancer(token); 64 | // access_token有效期,单位:秒 65 | setAccessTokenValiditySeconds(60 * 60 * 24 * 365 * 50); 66 | // refresh_token的有效期,单位:秒, 默认30天 67 | // 这决定了客户端选择“记住当前登录用户”的最长时效,即失效前都不用再请求用户赋权了 68 | setRefreshTokenValiditySeconds(60 * 60 * 24 * 15); 69 | // 是否支持refresh_token,默认false 70 | setSupportRefreshToken(true); 71 | // 是否复用refresh_token,默认为true 72 | // 如果为false,则每次请求刷新都会删除旧的refresh_token,创建新的refresh_token 73 | setReuseRefreshToken(true); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/security/RSA256PublicJWTAccessToken.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.infrastructure.security; 2 | 3 | import org.springframework.core.io.ClassPathResource; 4 | import org.springframework.core.io.Resource; 5 | import org.springframework.security.core.userdetails.UserDetailsService; 6 | import org.springframework.util.FileCopyUtils; 7 | 8 | import javax.inject.Named; 9 | import java.io.IOException; 10 | 11 | /** 12 | * 使用RSA SHA256公钥解密的JWT令牌 13 | * 可验证收到的请求是否通过在Security工程中的私钥加密的。 14 | * Spring Security也提供了jks-uri的形式进行自动验证,为了便于对比,就没有节省这几行代码 15 | * 16 | * @author icyfenix@gmail.com 17 | * @date 2020/7/17 15:15 18 | **/ 19 | @Named 20 | public class RSA256PublicJWTAccessToken extends JWTAccessToken { 21 | 22 | RSA256PublicJWTAccessToken(UserDetailsService userDetailsService) throws IOException { 23 | super(userDetailsService); 24 | Resource resource = new ClassPathResource("public.cert"); 25 | String publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream())); 26 | setVerifierKey(publicKey); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /bookstore-microservices-library-infrastructure/src/main/java/com/github/fenixsoft/bookstore/infrastructure/utility/Encryption.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2020. the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. More information from: 15 | * 16 | * https://github.com/fenixsoft 17 | */ 18 | 19 | package com.github.fenixsoft.bookstore.infrastructure.utility; 20 | 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 23 | import org.springframework.security.crypto.password.PasswordEncoder; 24 | 25 | import javax.inject.Named; 26 | import java.util.Optional; 27 | 28 | /** 29 | * 默认的加密工具 30 | * 31 | * @author icyfenix@gmail.com 32 | * @date 2020/3/10 18:02 33 | **/ 34 | @Named 35 | public class Encryption { 36 | 37 | /** 38 | * 配置认证使用的密码加密算法:BCrypt 39 | * 由于在Spring Security很多验证器中都要用到{@link PasswordEncoder}的加密,所以这里要添加@Bean注解发布出去 40 | */ 41 | @Bean 42 | public PasswordEncoder passwordEncoder() { 43 | return new BCryptPasswordEncoder(); 44 | } 45 | 46 | 47 | /** 48 | * 使用默认加密算法进行编码 49 | */ 50 | public String encode(CharSequence rawPassword) { 51 | return passwordEncoder().encode(Optional.ofNullable(rawPassword).orElse("")); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /bookstore-microservices-library-testing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-library-testing 13 | 14 | 15 | 16 | com.github.fenixsoft 17 | bookstore-microservices-library-infrastructure 18 | 1.0.0-SNAPSHOT 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-starter 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-test 27 | 28 | 29 | org.junit.vintage 30 | junit-vintage-engine 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /bookstore-microservices-library-testing/src/main/java/com/github/fenixsoft/bookstore/resource/DBRollbackBase.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.resource; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.extension.ExtendWith; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.cache.CacheManager; 7 | import org.springframework.test.context.ActiveProfiles; 8 | import org.springframework.test.context.jdbc.Sql; 9 | import org.springframework.test.context.junit.jupiter.SpringExtension; 10 | 11 | /** 12 | * 单元测试基类 13 | *

14 | * 提供了每个单元测试自动恢复数据库、清理缓存的处理 15 | * 16 | * @author icyfenix@gmail.com 17 | * @date 2020/4/7 14:19 18 | **/ 19 | @ActiveProfiles("test") 20 | @ExtendWith(SpringExtension.class) 21 | @Sql(scripts = {"classpath:db/hsqldb/schema.sql", "classpath:db/hsqldb/data.sql"}) 22 | public class DBRollbackBase { 23 | 24 | @Autowired 25 | private CacheManager cacheManager; 26 | 27 | @BeforeEach 28 | public void evictAllCaches() { 29 | for (String name : cacheManager.getCacheNames()) { 30 | cacheManager.getCache(name).clear(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /bookstore-microservices-library-testing/src/main/java/com/github/fenixsoft/bookstore/resource/mock/AccountServiceClientMock.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.resource.mock; 2 | 3 | import com.github.fenixsoft.bookstore.domain.account.Account; 4 | import com.github.fenixsoft.bookstore.domain.security.AccountServiceClient; 5 | 6 | import javax.inject.Named; 7 | 8 | /** 9 | * @author icyfenix@gmail.com 10 | * @date 2020/4/21 16:48 11 | **/ 12 | @Named 13 | public class AccountServiceClientMock implements AccountServiceClient { 14 | 15 | @Override 16 | public Account findByUsername(String username) { 17 | if (username.equals("icyfenix")) { 18 | Account icy = new Account(); 19 | icy.setId(1); 20 | icy.setUsername("icyfenix"); 21 | icy.setPassword("$2a$10$iIim4LtpT2yjxU2YVNDuO.yb1Z2lq86vYBZleAeuIh2aFXjyoMCM."); 22 | icy.setName("周志明"); 23 | icy.setTelephone("18888888888"); 24 | icy.setEmail("icyfenix@gmail.com"); 25 | icy.setLocation("唐家湾港湾大道科技一路3号远光软件股份有限公司"); 26 | return icy; 27 | } else { 28 | return null; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-configuration/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | 3 | MAINTAINER icyfenix 4 | 5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ 6 | JAVA_OPTS="" \ 7 | PORT=8888 \ 8 | PROFILES="native" 9 | 10 | ADD /target/*.jar /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_OPTS -jar /config.jar --spring.profiles.active=$PROFILES"] 17 | 18 | EXPOSE $PORT 19 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-configuration/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservice-platform-configuration 13 | 14 | 15 | 16 | org.springframework.cloud 17 | spring-cloud-config-server 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-actuator 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-maven-plugin 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-configuration/src/main/java/com/github/fenixsoft/bookstore/configuration/ConfigApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.configuration; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | /** 8 | * Spring Cloud配置中心 9 | * 10 | * @author icyfenix@gmail.com 11 | * @date 2020/4/17 16:25 12 | **/ 13 | @EnableConfigServer 14 | @SpringBootApplication 15 | public class ConfigApplication { 16 | public static void main(String[] args) { 17 | SpringApplication.run(ConfigApplication.class, args); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bookstore-microservices-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 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-configuration/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ______ _ ____ __ _____ __ 2 | / ____/__ ____ (_) __ / __ )____ ____ / /_/ ___// /_____ ________ 3 | / /_ / _ \/ __ \/ / |/_/ / __ / __ \/ __ \/ __/\__ \/ __/ __ \/ ___/ _ \ 4 | / __/ / __/ / / / /> < / /_/ / /_/ / /_/ / /_ ___/ / /_/ /_/ / / / __/ 5 | /_/ \___/_/ /_/_/_/|_| /_____/\____/\____/\__//____/\__/\____/_/ \___/ 6 | Configuration Center 7 | -------------------------------------------------------------------------------- /bookstore-microservices-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 | database: hsqldb 7 | 8 | spring: 9 | datasource: 10 | schema: "classpath:db/${database}/schema.sql" 11 | data: "classpath:db/${database}/data.sql" 12 | sql-script-encoding: UTF-8 13 | jpa: 14 | show-sql: false 15 | hibernate: 16 | ddl-auto: none 17 | open-in-view: false 18 | resources: 19 | chain: 20 | compressed: true 21 | cache: true 22 | cache: 23 | period: 86400 24 | 25 | security: 26 | oauth2: 27 | client: 28 | # OAuth的ClientID和ClientSecret是写在OAuthClientDetailsService中的 29 | # 实际生产中要考虑好如何获取验证服务器的Endpoint、动态增加微服务客户端、如何分发客户端密钥等问题,而在演示工程中并不关注这些 30 | clientId: account 31 | clientSecret: account_secret 32 | accessTokenUri: http://${AUTH_HOST:localhost}:${AUTH_PORT:8301}/oauth/token 33 | grant-type: client_credentials 34 | scope: SERVICE 35 | resource: 36 | userInfoUri: BUGFIX 37 | 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 | 45 | server: 46 | port: ${PORT:8401} 47 | -------------------------------------------------------------------------------- /bookstore-microservices-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 | -------------------------------------------------------------------------------- /bookstore-microservices-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 | database: hsqldb 7 | 8 | spring: 9 | datasource: 10 | schema: "classpath:db/${database}/schema.sql" 11 | data: "classpath:db/${database}/data.sql" 12 | sql-script-encoding: UTF-8 13 | jpa: 14 | show-sql: false 15 | hibernate: 16 | ddl-auto: none 17 | open-in-view: false 18 | resources: 19 | chain: 20 | compressed: true 21 | cache: true 22 | cache: 23 | period: 86400 24 | 25 | security: 26 | oauth2: 27 | client: 28 | # OAuth的ClientID和ClientSecret是写在OAuthClientDetailsService中的 29 | # 实际生产中要考虑好如何获取验证服务器的Endpoint、动态增加微服务客户端、如何分发客户端密钥等问题,而在演示工程中并不关注这些 30 | clientId: payment 31 | clientSecret: payment_secret 32 | accessTokenUri: http://${AUTH_HOST:localhost}:${AUTH_PORT:8301}/oauth/token 33 | grant-type: client_credentials 34 | scope: SERVICE 35 | resource: 36 | userInfoUri: BUGFIX 37 | 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 | 45 | server: 46 | port: ${PORT:8601} 47 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-configuration/src/main/resources/configurations/registry.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${PORT:8761} 3 | -------------------------------------------------------------------------------- /bookstore-microservices-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 | -------------------------------------------------------------------------------- /bookstore-microservices-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 | database: hsqldb 7 | 8 | spring: 9 | datasource: 10 | schema: "classpath:db/${database}/schema.sql" 11 | data: "classpath:db/${database}/data.sql" 12 | sql-script-encoding: UTF-8 13 | jpa: 14 | show-sql: false 15 | hibernate: 16 | ddl-auto: none 17 | open-in-view: false 18 | resources: 19 | chain: 20 | compressed: true 21 | cache: true 22 | cache: 23 | period: 86400 24 | 25 | security: 26 | oauth2: 27 | client: 28 | # OAuth的ClientID和ClientSecret是写在OAuthClientDetailsService中的 29 | # 实际生产中要考虑好如何获取验证服务器的Endpoint、动态增加微服务客户端、如何分发客户端密钥等问题,而在演示工程中并不关注这些 30 | clientId: warehouse 31 | clientSecret: warehouse_secret 32 | accessTokenUri: http://${AUTH_HOST:localhost}:${AUTH_PORT:8301}/oauth/token 33 | grant-type: client_credentials 34 | scope: SERVICE 35 | resource: 36 | userInfoUri: BUGFIX 37 | 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 | 45 | server: 46 | port: ${PORT:8501} 47 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:12-alpine 2 | 3 | MAINTAINER icyfenix 4 | 5 | ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \ 6 | JAVA_OPTS="" \ 7 | PORT=8080 \ 8 | CONFIG_PORT=8888 \ 9 | PROFILES="default" 10 | 11 | ADD /target/*.jar /gateway.jar 12 | 13 | ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /gateway.jar --spring.profiles.active=$PROFILES"] 14 | 15 | EXPOSE $PORT 16 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-platform-gateway 13 | 14 | 15 | 16 | org.springframework.cloud 17 | spring-cloud-starter-netflix-zuul 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-starter-config 22 | 23 | 24 | org.springframework.cloud 25 | spring-cloud-starter-netflix-eureka-client 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-maven-plugin 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/java/com/github/fenixsoft/bookstore/gateway/GatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.gateway; 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 | /** 9 | * SpringCloud Netflix全家桶的服务API网关 10 | * 11 | * @author icyfenix@gmail.com 12 | * @date 2020/4/17 17:50 13 | **/ 14 | @EnableZuulProxy 15 | @EnableDiscoveryClient 16 | @SpringBootApplication 17 | public class GatewayApplication { 18 | public static void main(String[] args) { 19 | SpringApplication.run(GatewayApplication.class, args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ______ _ ____ __ _____ __ 2 | / ____/__ ____ (_) __ / __ )____ ____ / /_/ ___// /_____ ________ 3 | / /_ / _ \/ __ \/ / |/_/ / __ / __ \/ __ \/ __/\__ \/ __/ __ \/ ___/ _ \ 4 | / __/ / __/ / / / /> < / /_/ / /_/ / /_/ / /_ ___/ / /_/ /_/ / / / __/ 5 | /_/ \___/_/ /_/_/_/|_| /_____/\____/\____/\__//____/\__/\____/_/ \___/ 6 | API Gateway 7 | -------------------------------------------------------------------------------- /bookstore-microservices-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 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/favicon.ico -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | Fenix's BookStore

-------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/board/gitalk.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 20 | 21 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/ai.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/fenix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/fenix.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/fenix2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/fenix2.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/jvm3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/carousel/jvm3.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/ai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/ai.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/fenix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/fenix.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvm1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvm1.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvm2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvm2.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvm3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvm3.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvms.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvms.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvms8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/jvms8.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/osgi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/cover/osgi.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/OSGi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/OSGi.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/ai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/ai.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/fenix.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/fenix.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/jvm2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/jvm2.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/jvm3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/jvm3.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/jvms.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/desc/jvms.jpg -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/fonts/element-icons.535877f.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/fonts/element-icons.535877f.woff -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/fonts/element-icons.732389d.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/fonts/element-icons.732389d.ttf -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/img/bg2.ef8085e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/img/bg2.ef8085e.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/img/cc-logo.3653e37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/img/cc-logo.3653e37.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/img/logo-color.5500ec5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/img/logo-color.5500ec5.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/img/logo-gray-light.84aa074.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenixsoft/microservice_arch_springcloud/29208692bf0abcce16cd55cfcca364f36fefc11f/bookstore-microservices-platform-gateway/src/main/resources/static/static/img/logo-gray-light.84aa074.png -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/js/0.c178f427b3d08777c70f.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([0],{"7WGw":function(t,e,s){"use strict";var a={name:"PayStepIndicator",props:{step:Number}},i={render:function(){var t=this.$createElement,e=this._self._c||t;return e("el-card",{staticClass:"box-card",staticStyle:{"margin-top":"20px"}},[e("div",{staticClass:"header",attrs:{slot:"header"},slot:"header"},[e("span",[this._v("购买流程")])]),this._v(" "),e("div",{staticClass:"content",staticStyle:{padding:"0 100px"}},[e("el-steps",{attrs:{active:this.step,"align-center":""}},[e("el-step",{attrs:{title:"我的购物车",description:"在购物车中确认每件商品的价格、数量"}}),this._v(" "),e("el-step",{attrs:{title:"我的结算单",description:"在结算单中确认配送地址、支付信息"}}),this._v(" "),e("el-step",{attrs:{title:"支付",description:"通过微信、支付宝完成付款,等待收货"}})],1)],1)])},staticRenderFns:[]};var n=s("VU/8")(a,i,!1,function(t){s("ne/a")},"data-v-9c9995a8",null);e.a=n.exports},"ne/a":function(t,e){}}); -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/js/8.176f9455c3442c06ebf6.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([8],{ZLgQ:function(t,e){},k7C0:function(t,e,a){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var s={render:function(){var t=this.$createElement,e=this._self._c||t;return e("el-card",{staticClass:"box-card",attrs:{"body-style":{padding:"0 10px 0 10px"}}},[e("div",{staticClass:"header",attrs:{slot:"header"},slot:"header"},[e("span",[this._v("讨论")]),this._v(" "),e("span",{staticClass:"comment"},[this._v("本功能通过Gitalk使用GitHub的Issues提供服务,请使用GitHub账号登录")])]),this._v(" "),e("div",[e("iframe",{staticStyle:{width:"1300px",height:"1000px"},attrs:{src:"/static/board/gitalk.html",frameborder:"0"}})])])},staticRenderFns:[]};var i=a("VU/8")({name:"CommentPage"},s,!1,function(t){a("ZLgQ")},"data-v-a8ab5f44",null);e.default=i.exports}}); -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/js/9.527be297aba1594ffe0d.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([9],{TgyC:function(t,e,a){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=a("Dd8w"),l=a.n(n),i=a("NYxO"),s={name:"CartPage",components:{PayStepIndicator:a("7WGw").a},data:function(){return{multipleSelection:[]}},computed:l()({},Object(i.e)("cart",["items"]),{total:function(){return this.multipleSelection.reduce(function(t,e){return t+e.price*e.amount},0)}}),mounted:function(){this.toggleSelection(this.items)},methods:l()({},Object(i.d)("cart",["adjustCartItems","removeCartItem"]),Object(i.b)("cart",["setupSettlementBillWithDefaultValue"]),{adjustAmount:function(t,e,a){var n=l()({},t);n.amount=e-a,this.adjustCartItems(n)},removeItem:function(t){var e=this;this.removeCartItem(t),this.$nextTick(function(){return e.toggleSelection(e.items)})},toggleSelection:function(t){var e=this;t?t.forEach(function(t){e.$refs.cartTable.toggleRowSelection(t)}):this.$refs.cartTable.clearSelection()},goSettlement:function(){this.setupSettlementBillWithDefaultValue({items:this.multipleSelection}),this.$router.push("/settle")},handleSelectionChange:function(t){this.multipleSelection=t}})},o={render:function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",[a("el-card",{staticClass:"box-card"},[a("div",{staticClass:"header",attrs:{slot:"header"},slot:"header"},[a("span",[t._v("我的购物车")]),t._v(" "),a("span",{staticClass:"comment"},[t._v("温馨提示:产品是否购买成功,以最终支付为准哦,请尽快完成结算")])]),t._v(" "),a("div",{staticClass:"content"},[a("el-table",{ref:"cartTable",staticStyle:{width:"100%"},attrs:{data:t.items},on:{"selection-change":t.handleSelectionChange}},[a("el-table-column",{attrs:{type:"selection",width:"55",fixed:"","show-overflow-tooltip":""}}),t._v(" "),a("el-table-column",{attrs:{label:"图片",width:"150"},scopedSlots:t._u([{key:"default",fn:function(t){return[a("img",{staticStyle:{width:"120px"},attrs:{src:t.row.cover}})]}}])}),t._v(" "),a("el-table-column",{attrs:{prop:"title",label:"商品名称",sortable:""}}),t._v(" "),a("el-table-column",{attrs:{prop:"price",label:"单价",width:"100",sortable:""}}),t._v(" "),a("el-table-column",{attrs:{label:"数量",width:"170",sortable:""},scopedSlots:t._u([{key:"default",fn:function(e){return[a("el-input-number",{attrs:{size:"mini",min:0,max:10,value:e.row.amount},on:{change:function(a,n){t.adjustAmount(e.row,a,n)}}})]}}])}),t._v(" "),a("el-table-column",{attrs:{label:"小计",width:"120",sortable:""},scopedSlots:t._u([{key:"default",fn:function(e){return[a("span",{staticClass:"subtotal"},[t._v(t._s(e.row.price*e.row.amount)+" 元")])]}}])}),t._v(" "),a("el-table-column",{attrs:{label:"操作",width:"120"},scopedSlots:t._u([{key:"default",fn:function(e){return[a("el-button",{attrs:{plain:"",size:"mini",type:"danger"},on:{click:function(a){return t.removeItem(e.row.id)}}},[t._v("删除")])]}}])})],1),t._v(" "),a("div",{staticClass:"actions"},[t._v("\n "+t._s("购物车中共计 "+t.items.length+" 件商品,已选择其中 "+t.multipleSelection.length+" 件")+"\n "),a("div",{staticClass:"total"},[t._v("\n 总计: "),a("span",{staticClass:"pay_price"},[t._v(t._s(this.total))]),t._v(" 元\n "),a("div",{staticClass:"pay_action"},[a("el-button",{staticStyle:{position:"relative",top:"-6px"},attrs:{size:"large",type:"primary",disabled:this.total<=0},on:{click:t.goSettlement}},[t._v("¥ 选好了,去结算\n ")])],1)])])],1)]),t._v(" "),a("PayStepIndicator",{attrs:{step:1}})],1)},staticRenderFns:[]};var r=a("VU/8")(s,o,!1,function(t){a("fn1c")},"data-v-1316e37e",null);e.default=r.exports},fn1c:function(t,e){}}); -------------------------------------------------------------------------------- /bookstore-microservices-platform-gateway/src/main/resources/static/static/js/manifest.0437a7f02d3154ee1abb.js: -------------------------------------------------------------------------------- 1 | !function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,a){for(var f,i,u,s=0,d=[];s 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-platform-registry 13 | 14 | 15 | 16 | org.springframework.cloud 17 | spring-cloud-starter-netflix-eureka-server 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-starter-config 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-actuator 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-maven-plugin 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-registry/src/main/java/com/github/fenixsoft/bookstore/registry/RegistryApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fenixsoft.bookstore.registry; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | /** 8 | * SpringCloud Netflix全家桶的服务发现注册 9 | * 10 | * @author icyfenix@gmail.com 11 | * @date 2020/4/17 17:29 12 | **/ 13 | @EnableEurekaServer 14 | @SpringBootApplication 15 | public class RegistryApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(RegistryApplication.class, args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-registry/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ______ _ ____ __ _____ __ 2 | / ____/__ ____ (_) __ / __ )____ ____ / /_/ ___// /_____ ________ 3 | / /_ / _ \/ __ \/ / |/_/ / __ / __ \/ __ \/ __/\__ \/ __/ __ \/ ___/ _ \ 4 | / __/ / __/ / / / /> < / /_/ / /_/ / /_/ / /_ ___/ / /_/ /_/ / / / __/ 5 | /_/ \___/_/ /_/_/_/|_| /_____/\____/\____/\__//____/\__/\____/_/ \___/ 6 | Service Discovery 7 | -------------------------------------------------------------------------------- /bookstore-microservices-platform-registry/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: registry 4 | cloud: 5 | config: 6 | uri: http://${CONFIG_HOST:localhost}:${CONFIG_PORT:8888} 7 | fail-fast: false 8 | username: user 9 | password: ${CONFIG_PASS:dev} 10 | 11 | eureka: 12 | instance: 13 | prefer-ip-address: true 14 | client: 15 | registerWithEureka: false 16 | fetchRegistry: false 17 | server: 18 | waitTimeInMsWhenSyncEmpty: 0 19 | -------------------------------------------------------------------------------- /bookstore-microservices-report-aggregation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | bookstore-microservice-springcloud 7 | com.github.fenixsoft 8 | 1.0.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | bookstore-microservices-report-aggregation 13 | 14 | 15 | 16 | com.github.fenixsoft 17 | bookstore-microservices-library-infrastructure 18 | 1.0.0-SNAPSHOT 19 | 20 | 21 | com.github.fenixsoft 22 | bookstore-microservices-domain-account 23 | 1.0.0-SNAPSHOT 24 | 25 | 26 | com.github.fenixsoft 27 | bookstore-microservices-domain-security 28 | 1.0.0-SNAPSHOT 29 | 30 | 31 | com.github.fenixsoft 32 | bookstore-microservices-domain-warehouse 33 | 1.0.0-SNAPSHOT 34 | 35 | 36 | com.github.fenixsoft 37 | bookstore-microservices-domain-payment 38 | 1.0.0-SNAPSHOT 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.jacoco 46 | jacoco-maven-plugin 47 | 0.8.5 48 | 49 | 50 | report-aggregate 51 | package 52 | 53 | report-aggregate 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | services: 3 | platform-configuration: 4 | build: bookstore-microservices-platform-configuration 5 | restart: always 6 | ports: 7 | - 8888:8888 8 | 9 | platform-registry: 10 | build: bookstore-microservices-platform-registry 11 | environment: 12 | CONFIG_HOST: platform-configuration 13 | restart: always 14 | depends_on: 15 | platform-configuration: 16 | condition: service_healthy 17 | ports: 18 | - 8761:8761 19 | 20 | platform-gateway: 21 | build: bookstore-microservices-platform-gateway 22 | depends_on: 23 | platform-configuration: 24 | condition: service_healthy 25 | environment: 26 | CONFIG_HOST: platform-configuration 27 | REGISTRY_HOST: platform-registry 28 | restart: always 29 | ports: 30 | - 8080:8080 31 | 32 | domain-security: 33 | build: bookstore-microservices-domain-security 34 | depends_on: 35 | platform-configuration: 36 | condition: service_healthy 37 | environment: 38 | CONFIG_HOST: platform-configuration 39 | REGISTRY_HOST: platform-registry 40 | restart: always 41 | ports: 42 | - 8301:8301 43 | 44 | domain-account: 45 | build: bookstore-microservices-domain-account 46 | depends_on: 47 | platform-configuration: 48 | condition: service_healthy 49 | environment: 50 | CONFIG_HOST: platform-configuration 51 | REGISTRY_HOST: platform-registry 52 | AUTH_HOST: domain-security 53 | restart: always 54 | ports: 55 | - 8401:8401 56 | 57 | domain-warehouse: 58 | build: bookstore-microservices-domain-warehouse 59 | depends_on: 60 | platform-configuration: 61 | condition: service_healthy 62 | environment: 63 | CONFIG_HOST: platform-configuration 64 | REGISTRY_HOST: platform-registry 65 | AUTH_HOST: domain-security 66 | restart: always 67 | ports: 68 | - 8501:8501 69 | 70 | domain-payment: 71 | build: bookstore-microservices-domain-payment 72 | depends_on: 73 | platform-configuration: 74 | condition: service_healthy 75 | environment: 76 | CONFIG_HOST: platform-configuration 77 | REGISTRY_HOST: platform-registry 78 | AUTH_HOST: domain-security 79 | restart: always 80 | ports: 81 | - 8601:8601 82 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | services: 3 | platform-configuration: 4 | image: icyfenix/bookstore-springcloud:platform-configuration 5 | restart: always 6 | ports: 7 | - 8888:8888 8 | 9 | platform-registry: 10 | image: icyfenix/bookstore-springcloud:platform-registry 11 | environment: 12 | CONFIG_HOST: platform-configuration 13 | restart: always 14 | depends_on: 15 | platform-configuration: 16 | condition: service_healthy 17 | ports: 18 | - 8761:8761 19 | 20 | platform-gateway: 21 | image: icyfenix/bookstore-springcloud:platform-gateway 22 | depends_on: 23 | platform-configuration: 24 | condition: service_healthy 25 | platform-registry: 26 | condition: service_healthy 27 | environment: 28 | CONFIG_HOST: platform-configuration 29 | REGISTRY_HOST: platform-registry 30 | restart: always 31 | ports: 32 | - 8080:8080 33 | 34 | domain-security: 35 | image: icyfenix/bookstore-springcloud:domain-security 36 | depends_on: 37 | platform-configuration: 38 | condition: service_healthy 39 | platform-registry: 40 | condition: service_healthy 41 | environment: 42 | CONFIG_HOST: platform-configuration 43 | REGISTRY_HOST: platform-registry 44 | restart: always 45 | ports: 46 | - 8301:8301 47 | 48 | domain-account: 49 | image: icyfenix/bookstore-springcloud:domain-account 50 | depends_on: 51 | platform-configuration: 52 | condition: service_healthy 53 | platform-registry: 54 | condition: service_healthy 55 | environment: 56 | CONFIG_HOST: platform-configuration 57 | REGISTRY_HOST: platform-registry 58 | AUTH_HOST: domain-security 59 | restart: always 60 | ports: 61 | - 8401:8401 62 | 63 | domain-warehouse: 64 | image: icyfenix/bookstore-springcloud:domain-warehouse 65 | depends_on: 66 | platform-configuration: 67 | condition: service_healthy 68 | platform-registry: 69 | condition: service_healthy 70 | environment: 71 | CONFIG_HOST: platform-configuration 72 | REGISTRY_HOST: platform-registry 73 | AUTH_HOST: domain-security 74 | restart: always 75 | ports: 76 | - 8501:8501 77 | 78 | domain-payment: 79 | image: icyfenix/bookstore-springcloud:domain-payment 80 | depends_on: 81 | platform-configuration: 82 | condition: service_healthy 83 | platform-registry: 84 | condition: service_healthy 85 | environment: 86 | CONFIG_HOST: platform-configuration 87 | REGISTRY_HOST: platform-registry 88 | AUTH_HOST: domain-security 89 | restart: always 90 | ports: 91 | - 8601:8601 92 | -------------------------------------------------------------------------------- /travis_docker_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin 3 | 4 | # configuration 5 | cd ./bookstore-microservices-platform-configuration/ 6 | docker build -t bookstore-springcloud:platform-configuration . 7 | docker tag bookstore-springcloud:platform-configuration $DOCKER_USERNAME/bookstore-springcloud:platform-configuration 8 | cd .. 9 | 10 | # registry 11 | cd ./bookstore-microservices-platform-registry/ 12 | docker build -t bookstore-springcloud:platform-registry . 13 | docker tag bookstore-springcloud:platform-registry $DOCKER_USERNAME/bookstore-springcloud:platform-registry 14 | cd .. 15 | 16 | # gateway 17 | cd ./bookstore-microservices-platform-gateway/ 18 | docker build -t bookstore-springcloud:platform-gateway . 19 | docker tag bookstore-springcloud:platform-gateway $DOCKER_USERNAME/bookstore-springcloud:platform-gateway 20 | cd .. 21 | 22 | # security 23 | cd ./bookstore-microservices-domain-security/ 24 | docker build -t bookstore-springcloud:domain-security . 25 | docker tag bookstore-springcloud:domain-security $DOCKER_USERNAME/bookstore-springcloud:domain-security 26 | cd .. 27 | 28 | # account 29 | cd ./bookstore-microservices-domain-account/ 30 | docker build -t bookstore-springcloud:domain-account . 31 | docker tag bookstore-springcloud:domain-account $DOCKER_USERNAME/bookstore-springcloud:domain-account 32 | cd .. 33 | 34 | # warehouse 35 | cd ./bookstore-microservices-domain-warehouse/ 36 | docker build -t bookstore-springcloud:domain-warehouse . 37 | docker tag bookstore-springcloud:domain-warehouse $DOCKER_USERNAME/bookstore-springcloud:domain-warehouse 38 | cd .. 39 | 40 | # payment 41 | cd ./bookstore-microservices-domain-payment/ 42 | docker build -t bookstore-springcloud:domain-payment . 43 | docker tag bookstore-springcloud:domain-payment $DOCKER_USERNAME/bookstore-springcloud:domain-payment 44 | cd .. 45 | 46 | docker images 47 | docker push $DOCKER_USERNAME/bookstore-springcloud:platform-configuration 48 | docker push $DOCKER_USERNAME/bookstore-springcloud:platform-registry 49 | docker push $DOCKER_USERNAME/bookstore-springcloud:platform-gateway 50 | docker push $DOCKER_USERNAME/bookstore-springcloud:domain-security 51 | docker push $DOCKER_USERNAME/bookstore-springcloud:domain-account 52 | docker push $DOCKER_USERNAME/bookstore-springcloud:domain-warehouse 53 | docker push $DOCKER_USERNAME/bookstore-springcloud:domain-payment 54 | --------------------------------------------------------------------------------