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 extends Account> 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 extends Payload>[] 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 extends Payload>[] 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 extends Payload>[] 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 extends Payload>[] 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 extends Payload>[] 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 |
--------------------------------------------------------------------------------