├── .gitignore
├── LICENSE
├── README.md
├── demo-email
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── email
│ │ ├── EmailAppApplication.java
│ │ ├── config
│ │ ├── MailAccountConfig.java
│ │ └── MailAccountProperties.java
│ │ ├── ctrl
│ │ └── EmailController.java
│ │ └── service
│ │ ├── EmailService.java
│ │ └── impl
│ │ └── EmailServiceImpl.java
│ └── resources
│ ├── application.yaml
│ └── static
│ └── tamplate.html
├── demo-flyway
├── pom.xml
└── src
│ └── main
│ └── resources
│ ├── application.yaml
│ └── db
│ └── migration
│ └── V20220601.1__user.sql
├── demo-google_authenticator
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── zzq
│ │ └── authenticator
│ │ ├── GoogleAuthenticatorAppApplication.java
│ │ └── config
│ │ └── GoogleAuthenticator.java
│ └── test
│ └── java
│ └── com
│ └── zzq
│ └── authenticator
│ └── AuthTest.java
├── demo-http
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── http
│ │ ├── HttpAppApplication.java
│ │ ├── config
│ │ └── RestTemplateConfig.java
│ │ └── ctrl
│ │ └── RestTemplateController.java
│ └── resources
│ └── application.yaml
├── demo-i18n
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── i18n
│ │ ├── I18NAppApplication.java
│ │ ├── config
│ │ └── MyLocaleResolver.java
│ │ ├── ctrl
│ │ └── LangController.java
│ │ └── util
│ │ └── I18nUtil.java
│ └── resources
│ ├── application.yaml
│ └── i18n
│ ├── messages_en_CA.properties
│ ├── messages_fr_CA.properties
│ └── messages_zh_CN.properties
├── demo-justauth
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── justauth
│ │ ├── JustAuthAppApplication.java
│ │ ├── config
│ │ └── JustAuthConfig.java
│ │ ├── ctrl
│ │ ├── GithubLoginController.java
│ │ ├── GoogleLoginController.java
│ │ └── WechatLoginController.java
│ │ └── properties
│ │ ├── GithubProperties.java
│ │ ├── GoogleProperties.java
│ │ └── WechatProperties.java
│ └── resources
│ └── application.yaml
├── demo-limiter
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── limiter
│ │ ├── LimiterAppApplication.java
│ │ ├── annotation
│ │ └── RateLimiter.java
│ │ ├── aop
│ │ └── RateLimiterAspect.java
│ │ ├── config
│ │ └── RedisConfig.java
│ │ ├── ctrl
│ │ └── LimiterController.java
│ │ ├── exception
│ │ └── LimiterException.java
│ │ ├── handler
│ │ └── GlobalExceptionHandler.java
│ │ └── util
│ │ └── IpUtil.java
│ └── resources
│ └── application.yaml
├── demo-multithreading
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── multithreading
│ │ ├── MultiThreadingAppApplication.java
│ │ ├── call
│ │ └── AsyncServiceCall.java
│ │ ├── config
│ │ └── ExecutorConfig.java
│ │ ├── ctrl
│ │ └── AsyncController.java
│ │ ├── run
│ │ └── AsyncServiceRun.java
│ │ └── service
│ │ ├── AsyncService.java
│ │ └── impl
│ │ └── AsyncServiceImpl.java
│ └── resources
│ ├── application.yaml
│ └── static
│ └── upload
│ └── a.pdf
├── demo-poi
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── poi
│ │ ├── PoiAppApplication.java
│ │ ├── ctrl
│ │ └── PoiController.java
│ │ ├── pojo
│ │ └── User.java
│ │ └── service
│ │ ├── PoiService.java
│ │ └── impl
│ │ └── PoiServiceImpl.java
│ └── resources
│ └── application.yaml
├── demo-quartz
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── quartz
│ │ ├── QuartzAppApplication.java
│ │ ├── config
│ │ └── QuartzConfig.java
│ │ ├── job
│ │ └── FirstJob.java
│ │ └── scheduled
│ │ └── AnnotationScheduled.java
│ └── resources
│ └── application.yaml
├── demo-rabbitmq
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── rabbitmq
│ │ ├── RabbitMqAppApplication.java
│ │ ├── amqp
│ │ └── ConsumerWorker.java
│ │ ├── config
│ │ └── AmqpConfig.java
│ │ └── ctrl
│ │ └── ProducerController.java
│ └── resources
│ └── application.yaml
├── demo-redis
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── redis
│ │ ├── RedisAppApplication.java
│ │ ├── config
│ │ ├── CacheManagerConfig.java
│ │ └── RedisTemplateConfig.java
│ │ ├── ctrl
│ │ └── RedisController.java
│ │ └── service
│ │ ├── RedisService.java
│ │ └── impl
│ │ └── RedisServiceImpl.java
│ └── resources
│ └── application.yaml
├── demo-security_jwt
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── security
│ │ ├── SecurityJWTAppApplication.java
│ │ ├── annotation
│ │ └── Anonymous.java
│ │ ├── bean
│ │ ├── Token.java
│ │ └── TokenImpl.java
│ │ ├── config
│ │ ├── CS.java
│ │ └── WebSecurityConfig.java
│ │ ├── ctrl
│ │ └── LoginController.java
│ │ ├── dto
│ │ └── LoginRequest.java
│ │ ├── entity
│ │ ├── Permission.java
│ │ ├── Role.java
│ │ ├── RolePermission.java
│ │ ├── User.java
│ │ └── UserRole.java
│ │ ├── filter
│ │ └── TokenFilter.java
│ │ ├── mapper
│ │ ├── PermissionMapper.java
│ │ ├── RoleMapper.java
│ │ ├── RolePermissionMapper.java
│ │ ├── UserMapper.java
│ │ ├── UserRoleMapper.java
│ │ └── xml
│ │ │ ├── PermissionMapper.xml
│ │ │ ├── RoleMapper.xml
│ │ │ ├── RolePermissionMapper.xml
│ │ │ ├── UserMapper.xml
│ │ │ └── UserRoleMapper.xml
│ │ ├── service
│ │ ├── LoginService.java
│ │ ├── TokenService.java
│ │ └── impl
│ │ │ ├── LoginServiceImpl.java
│ │ │ └── TokenServiceImpl.java
│ │ └── utils
│ │ └── SecContextUtil.java
│ └── resources
│ ├── application.yaml
│ └── sql
│ └── security_jwt.sql
├── demo-swagger
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── swagger
│ │ ├── SwaggerAppApplication.java
│ │ ├── config
│ │ └── SwaggerConfig.java
│ │ └── ctrl
│ │ └── SwaggerController.java
│ └── resources
│ └── application.yaml
├── demo-websocket
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── zzq
│ │ └── websocket
│ │ ├── WebSocketAppApplication.java
│ │ ├── config
│ │ └── WebSocketConfig.java
│ │ └── server
│ │ └── WebSocketServer.java
│ └── resources
│ └── index.html
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | maven
2 | packages
3 | *.log
4 | target
5 | mvnw
6 | mvnw.cmd
7 |
8 | /.mvn
9 | /.idea
10 | ./**/*.iml
11 | */**/target
12 | */**/.settings
13 | */**/.project
14 | */**/.classpath
15 | */**/.mvn
16 | */**/.idea
17 | */**/publish
18 | */**/node_modules
19 | */**/dist-rollup
20 | */**/out-tsc
21 | */**/out
22 |
23 | !maven/config
24 | *.iml
25 | *.jar
26 |
27 | ### STS ###
28 | .apt_generated
29 | .classpath
30 | .factorypath
31 | .project
32 | .settings
33 | .springBeans
34 | .sts4-cache
35 |
36 | ### IntelliJ IDEA ###
37 | .idea
38 | .mvn
39 | *.iws
40 | *.iml
41 | *.ipr
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # springboot-summary
2 | Springboot framework combined with other components
3 |
--------------------------------------------------------------------------------
/demo-email/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-email
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 |
23 | javax.mail
24 | mail
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-logging
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-validation
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-web
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-actuator
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-test
50 |
51 |
52 |
53 |
54 | org.mariadb.jdbc
55 | mariadb-java-client
56 | runtime
57 |
58 |
59 |
60 |
61 | cn.hutool
62 | hutool-all
63 |
64 |
65 |
66 | org.projectlombok
67 | lombok
68 | true
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/demo-email/src/main/java/com/zzq/email/EmailAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.email;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class EmailAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(EmailAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-email/src/main/java/com/zzq/email/config/MailAccountConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.email.config;
2 |
3 | import cn.hutool.extra.mail.MailAccount;
4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | @Configuration
9 | @ConditionalOnBean(MailAccountProperties.class)
10 | public class MailAccountConfig {
11 |
12 | @Bean
13 | public MailAccount mailAccount(MailAccountProperties mailAccountProperties) {
14 | MailAccount mailAccount = new MailAccount();
15 | mailAccount.setHost(mailAccountProperties.getHost());
16 | mailAccount.setPort(mailAccountProperties.getPort());
17 | mailAccount.setAuth(mailAccountProperties.getAuth());
18 | mailAccount.setFrom(mailAccountProperties.getFrom());
19 | mailAccount.setUser(mailAccountProperties.getUser());
20 | mailAccount.setPass(mailAccountProperties.getPass());
21 | return mailAccount;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/demo-email/src/main/java/com/zzq/email/config/MailAccountProperties.java:
--------------------------------------------------------------------------------
1 | package com.zzq.email.config;
2 |
3 |
4 | import lombok.Data;
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Data
9 | @Component
10 | @ConfigurationProperties(prefix = MailAccountProperties.PREFIX)
11 | public class MailAccountProperties {
12 | public static final String PREFIX = "mail.account";
13 |
14 | private String host;
15 | private Integer port;
16 | private Boolean auth;
17 | private String from;
18 | private String user;
19 | private String pass;
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/demo-email/src/main/java/com/zzq/email/ctrl/EmailController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.email.ctrl;
2 |
3 |
4 | import com.zzq.email.service.EmailService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.PathVariable;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | @RestController
11 | @RequiredArgsConstructor
12 | public class EmailController {
13 |
14 | private final EmailService emailService;
15 |
16 | @GetMapping("/email/{emailAddress}")
17 | public String sendEmail(@PathVariable String emailAddress) {
18 | emailService.sendEmail(emailAddress);
19 | return "success";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/demo-email/src/main/java/com/zzq/email/service/EmailService.java:
--------------------------------------------------------------------------------
1 | package com.zzq.email.service;
2 |
3 | public interface EmailService {
4 | void sendEmail(String emailAddress);
5 | }
6 |
--------------------------------------------------------------------------------
/demo-email/src/main/java/com/zzq/email/service/impl/EmailServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzq.email.service.impl;
2 |
3 | import cn.hutool.core.collection.CollUtil;
4 | import cn.hutool.extra.mail.MailAccount;
5 | import cn.hutool.extra.mail.MailUtil;
6 | import com.zzq.email.config.MailAccountProperties;
7 | import com.zzq.email.service.EmailService;
8 | import lombok.RequiredArgsConstructor;
9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
10 | import org.springframework.stereotype.Service;
11 |
12 | import java.io.BufferedReader;
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.io.InputStreamReader;
16 | import java.text.MessageFormat;
17 |
18 |
19 | @Service
20 | @RequiredArgsConstructor
21 | @ConditionalOnBean(MailAccountProperties.class)
22 | public class EmailServiceImpl implements EmailService {
23 |
24 | private final MailAccount mailAccount;
25 |
26 | @Override
27 | public void sendEmail(String emailAddress) {
28 |
29 | MailUtil.send(mailAccount, CollUtil.newArrayList(emailAddress), "Zhou-Test", scopeTemplate(), true);
30 | }
31 |
32 | @SuppressWarnings("all")
33 | public String scopeTemplate() {
34 | String filename = "static\\tamplate.html";
35 | InputStream inputStream = ClassLoader.getSystemResourceAsStream(filename);
36 | BufferedReader fileReader = new BufferedReader(new InputStreamReader(inputStream));
37 | StringBuilder buffer = new StringBuilder();
38 | String line;
39 | try {
40 | while ((line = fileReader.readLine()) != null) {
41 | buffer.append(line);
42 | }
43 | } catch (IOException e) {
44 | e.printStackTrace();
45 | } finally {
46 | try {
47 | inputStream.close();
48 | } catch (Exception e) {
49 | e.printStackTrace();
50 | }
51 | try {
52 | fileReader.close();
53 | } catch (Exception e) {
54 | e.printStackTrace();
55 | }
56 | }
57 |
58 | long round = Math.round((Math.random() + 1) * 1000);
59 | String contentText = round + "";
60 |
61 |
62 | String inscription = "Test-Zhou";
63 | return MessageFormat.format(buffer.toString(), contentText, inscription);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/demo-email/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | mail:
2 | account:
3 | host: smtp.163.com
4 | port: 25
5 | auth: true
6 | from: zzq071798@163.com
7 | user: zzq071798@163.com
8 | pass: MPMBGLGYDBBFLZSN
9 |
--------------------------------------------------------------------------------
/demo-email/src/main/resources/static/tamplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
22 |
23 |
Hi your verify code is:
24 |
{0}
25 |
26 |
{1}
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/demo-flyway/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-flyway
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-logging
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-validation
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-web
34 |
35 |
36 |
37 |
38 | org.flywaydb
39 | flyway-core
40 |
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-actuator
46 |
47 |
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-starter-test
52 |
53 |
54 |
55 |
56 | org.mariadb.jdbc
57 | mariadb-java-client
58 | runtime
59 |
60 |
61 |
62 |
63 | cn.hutool
64 | hutool-all
65 |
66 |
67 |
68 |
69 | org.projectlombok
70 | lombok
71 | true
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/demo-flyway/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | management:
2 | server:
3 | port: 9001
4 | endpoints:
5 | web:
6 | base-path: /actuator
7 | exposure:
8 | include: "*"
9 | endpoint:
10 | health:
11 | show-details: always
12 | spring:
13 | flyway:
14 | out-of-order: true
15 | clean-disabled: true
16 | fail-on-missing-locations: true
17 | #####################################################################################################################
18 | # default location = db.migration
19 | # create table manually
20 | # CREATE TABLE IF NOT EXISTS flyway_schema_history
21 | # (
22 | # installed_rank INT NOT NULL
23 | # PRIMARY KEY,
24 | # VERSION VARCHAR(50) NULL,
25 | # description VARCHAR(200) NOT NULL,
26 | # TYPE VARCHAR(20) NOT NULL,
27 | # script VARCHAR(1000) NOT NULL,
28 | # CHECKSUM INT NULL,
29 | # installed_by VARCHAR(100) NOT NULL,
30 | # installed_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
31 | # execution_time INT NOT NULL,
32 | # success TINYINT(1) NOT NULL
33 | # );
34 | #
35 | # CREATE INDEX flyway_schema_history_s_idx
36 | # ON flyway_schema_history (success);
37 | #####################################################################################################################
38 |
39 |
40 |
--------------------------------------------------------------------------------
/demo-flyway/src/main/resources/db/migration/V20220601.1__user.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS `user`;
2 |
3 | CREATE TABLE `user` (
4 | `user_id` bigint(20) unsigned NOT NULL,
5 | `user_name` varchar(32) NOT NULL,
6 | `user_role_id` bigint(20) NOT NULL,
7 | PRIMARY KEY (`user_id`)
8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
9 |
--------------------------------------------------------------------------------
/demo-google_authenticator/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-google_authenticator
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-logging
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-validation
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-web
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-actuator
39 |
40 |
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-test
45 |
46 |
47 |
48 |
49 | org.mariadb.jdbc
50 | mariadb-java-client
51 | runtime
52 |
53 |
54 |
55 |
56 | cn.hutool
57 | hutool-all
58 |
59 |
60 |
61 | org.projectlombok
62 | lombok
63 | true
64 |
65 |
66 | commons-codec
67 | commons-codec
68 |
69 |
70 | org.springframework.boot
71 | spring-boot-starter-test
72 |
73 |
74 | junit
75 | junit
76 | test
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/demo-google_authenticator/src/main/java/com/zzq/authenticator/GoogleAuthenticatorAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.authenticator;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class GoogleAuthenticatorAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(GoogleAuthenticatorAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-google_authenticator/src/main/java/com/zzq/authenticator/config/GoogleAuthenticator.java:
--------------------------------------------------------------------------------
1 | package com.zzq.authenticator.config;
2 |
3 |
4 | import org.apache.commons.codec.binary.Base32;
5 | import org.apache.commons.codec.binary.Base64;
6 | import javax.crypto.Mac;
7 | import javax.crypto.spec.SecretKeySpec;
8 | import java.security.InvalidKeyException;
9 | import java.security.NoSuchAlgorithmException;
10 | import java.security.SecureRandom;
11 |
12 | public class GoogleAuthenticator {
13 |
14 | public static final int SECRET_SIZE = 10;
15 | public static final String SEED = "g8GjEvTbW5oVSV7avL47357438reyhreyuryetredLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx";
16 | public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG";
17 | // default 3 - max 17
18 | int window_size = 3;
19 |
20 | // 30 s each
21 | public void setWindowSize(int s) {
22 | if (s >= 1 && s <= 17)
23 | window_size = s;
24 | }
25 |
26 |
27 | public static String generateSecretKey() {
28 | SecureRandom sr = null;
29 | try {
30 | sr = SecureRandom.getInstance(RANDOM_NUMBER_ALGORITHM);
31 | sr.setSeed(Base64.decodeBase64(SEED));
32 | byte[] buffer = sr.generateSeed(SECRET_SIZE);
33 | Base32 codec = new Base32();
34 | byte[] bEncodedKey = codec.encode(buffer);
35 | return new String(bEncodedKey);
36 | } catch (NoSuchAlgorithmException e) {
37 | // should never occur... configuration error
38 | }
39 | return null;
40 | }
41 |
42 |
43 | public static String getQRBarcodeURL(String user, String host, String secret) {
44 | String format = "http://www.google.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=otpauth://totp/%s@%s?secret=%s";
45 | return String.format(format, user, host, secret);
46 | }
47 |
48 |
49 | public static String getQRBarcode(String user, String secret) {
50 | String format = "otpauth://totp/%s?secret=%s";
51 | return String.format(format, user, secret);
52 | }
53 |
54 |
55 | public boolean check_code(String secret, long code, long timeMsec) {
56 | Base32 codec = new Base32();
57 | byte[] decodedKey = codec.decode(secret);
58 | // convert unix msec time into a 30 second "window"
59 | // this is per the TOTP spec (see the RFC for details)
60 | long t = (timeMsec / 1000L) / 30L;
61 | // Window is used to check codes generated in the near past.
62 | // You can use this value to tune how far you're willing to go.
63 | for (int i = -window_size; i <= window_size; ++i) {
64 | long hash;
65 | try {
66 | hash = verify_code(decodedKey, t + i);
67 | } catch (Exception e) {
68 | // Yes, this is bad form - but
69 | // the exceptions thrown would be rare and a static
70 | // configuration problem
71 | e.printStackTrace();
72 | throw new RuntimeException(e.getMessage());
73 | // return false;
74 | }
75 | if (hash == code) {
76 | return true;
77 | }
78 | }
79 | // The validation code is invalid.
80 | return false;
81 | }
82 |
83 | private static int verify_code(byte[] key, long t) throws NoSuchAlgorithmException, InvalidKeyException {
84 | byte[] data = new byte[8];
85 | long value = t;
86 | for (int i = 8; i-- > 0; value >>>= 8) {
87 | data[i] = (byte) value;
88 | }
89 | SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1");
90 | Mac mac = Mac.getInstance("HmacSHA1");
91 | mac.init(signKey);
92 | byte[] hash = mac.doFinal(data);
93 | int offset = hash[20 - 1] & 0xF;
94 | // We're using a long because Java hasn't got unsigned int.
95 | long truncatedHash = 0;
96 | for (int i = 0; i < 4; ++i) {
97 | truncatedHash <<= 8;
98 | // We are dealing with signed bytes:
99 | // we just keep the first byte.
100 | truncatedHash |= (hash[offset + i] & 0xFF);
101 | }
102 | truncatedHash &= 0x7FFFFFFF;
103 | truncatedHash %= 1000000;
104 | return (int) truncatedHash;
105 | }
106 |
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/demo-google_authenticator/src/test/java/com/zzq/authenticator/AuthTest.java:
--------------------------------------------------------------------------------
1 | package com.zzq.authenticator;
2 |
3 | import com.zzq.authenticator.config.GoogleAuthenticator;
4 |
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.context.junit4.SpringRunner;
9 |
10 |
11 | @RunWith(SpringRunner.class)
12 | @SpringBootTest
13 | public class AuthTest {
14 | // private static String secret="ORDNFVBNA53H5ICA";
15 | // private static String secret="HQ53C3M4MWQJUVXD";
16 | private static String secret="EC2VIL5SKQSOQXCR";
17 |
18 |
19 | @Test
20 | public void generateSecretQrCodeURLTest(){
21 | secret = GoogleAuthenticator.generateSecretKey();
22 | String qrBarcodeURL = GoogleAuthenticator.getQRBarcodeURL("13212213239", "www.zzq.com", secret);
23 | System.out.println("qrBarcodeURL:" + qrBarcodeURL + ",key:" + secret);
24 | }
25 |
26 | @Test
27 | public void generateSecretQrCodeTest() {
28 | // different user with different secret
29 | secret = GoogleAuthenticator.generateSecretKey();
30 | String qrcode = GoogleAuthenticator.getQRBarcode("qq1962811421@gmail.com", secret);
31 | System.out.println("qrcode:" + qrcode + ",key:" + secret);
32 | }
33 |
34 |
35 | @Test
36 | public void verifyTest() {
37 | // if code start with 0 then delete 0
38 | long code = 532250;
39 | long t = System.currentTimeMillis();
40 | GoogleAuthenticator ga = new GoogleAuthenticator();
41 | ga.setWindowSize(1);
42 | boolean r = ga.check_code(secret, code, t);
43 | System.out.println("检查code是否正确?" + r);
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/demo-http/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-http
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-logging
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-validation
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-web
39 |
40 |
41 |
42 |
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-test
47 |
48 |
49 |
50 |
51 | org.mariadb.jdbc
52 | mariadb-java-client
53 | runtime
54 |
55 |
56 |
57 |
58 | cn.hutool
59 | hutool-all
60 |
61 |
62 |
63 |
64 | org.projectlombok
65 | lombok
66 | true
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/demo-http/src/main/java/com/zzq/http/HttpAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.http;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class HttpAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(HttpAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-http/src/main/java/com/zzq/http/config/RestTemplateConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.http.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.client.RestTemplate;
6 |
7 | @Configuration
8 | public class RestTemplateConfig {
9 |
10 |
11 | @Bean
12 | public RestTemplate restTemplate(){
13 | return new RestTemplate();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo-http/src/main/java/com/zzq/http/ctrl/RestTemplateController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.http.ctrl;
2 |
3 | import cn.hutool.json.JSONUtil;
4 | import lombok.RequiredArgsConstructor;
5 | import org.springframework.core.io.InputStreamResource;
6 | import org.springframework.http.*;
7 | import org.springframework.util.LinkedMultiValueMap;
8 | import org.springframework.util.MultiValueMap;
9 | import org.springframework.web.bind.annotation.*;
10 | import org.springframework.web.client.RestTemplate;
11 | import org.springframework.web.multipart.MultipartFile;
12 |
13 | import java.io.IOException;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 |
18 | @RestController
19 | @RequiredArgsConstructor
20 | public class RestTemplateController {
21 |
22 | private final RestTemplate restTemplate;
23 |
24 | @GetMapping("/test1/{name}")
25 | public ResponseEntity test1(@PathVariable String name) {
26 |
27 | return ResponseEntity.ok(name);
28 | }
29 |
30 | @GetMapping("/test2")
31 | public ResponseEntity test2(@RequestParam String name) {
32 |
33 | return ResponseEntity.ok(name);
34 | }
35 |
36 | @PostMapping("/test3")
37 | public ResponseEntity test3(@RequestBody Map map) {
38 | return ResponseEntity.ok(map);
39 | }
40 |
41 | @PostMapping("/test4")
42 | public ResponseEntity test4(MultipartFile file) {
43 |
44 | return ResponseEntity.ok(file.getOriginalFilename());
45 | }
46 |
47 |
48 | @GetMapping("/get1")
49 | public ResponseEntity get1() {
50 | String url = "http://localhost:8080/test1/{name}";
51 |
52 | Map varParams = new HashMap<>();
53 | varParams.put("name", "zzq");
54 |
55 | return restTemplate.exchange(url, HttpMethod.GET, null, String.class, varParams);
56 | }
57 |
58 |
59 | @GetMapping("/get2")
60 | public ResponseEntity get2() {
61 | String url = "http://localhost:8080/test2";
62 |
63 | Map varParams = new HashMap<>();
64 | varParams.put("name", "zzq");
65 |
66 | return restTemplate.exchange(url + "?name={name}", HttpMethod.GET, null, String.class, varParams);
67 | }
68 |
69 | @GetMapping("/get3")
70 | public ResponseEntity get3() {
71 | String url = "http://localhost:8080/test3";
72 |
73 | HttpHeaders headers = new HttpHeaders();
74 | headers.setContentType(MediaType.APPLICATION_JSON);
75 |
76 | Map map = new HashMap<>();
77 | map.put("name", "zzq");
78 | map.put("age", "18");
79 |
80 | HttpEntity requestEntity = new HttpEntity<>(JSONUtil.toJsonStr(map), headers);
81 |
82 | return restTemplate.exchange(url, HttpMethod.POST, requestEntity, Object.class);
83 | }
84 |
85 | @PostMapping("/get4")
86 | public ResponseEntity get4(MultipartFile multipartFile) throws IOException {
87 | String url = "http://localhost:8080/test4";
88 |
89 | HttpHeaders headers = new HttpHeaders();
90 | headers.setContentType(MediaType.MULTIPART_FORM_DATA);
91 |
92 | MultiValueMap map = new LinkedMultiValueMap<>();
93 |
94 | InputStreamResource fileResource = new InputStreamResource(multipartFile.getInputStream()) {
95 | @Override
96 | public long contentLength() {
97 | return multipartFile.getSize();
98 | }
99 |
100 | @Override
101 | public String getFilename() {
102 | return multipartFile.getOriginalFilename();
103 | }
104 | };
105 |
106 | map.add("file", fileResource);
107 | HttpEntity requestEntity = new HttpEntity<>(map, headers);
108 |
109 | return restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
110 | }
111 |
112 |
113 | }
114 |
115 |
--------------------------------------------------------------------------------
/demo-http/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhou1998ZQ/springboot-summary/0472bd7546604d231b54a696c2848dcd08226d68/demo-http/src/main/resources/application.yaml
--------------------------------------------------------------------------------
/demo-i18n/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-i18n
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-logging
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-validation
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-web
33 |
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-actuator
38 |
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-test
44 |
45 |
46 |
47 |
48 | org.mariadb.jdbc
49 | mariadb-java-client
50 | runtime
51 |
52 |
53 |
54 |
55 | cn.hutool
56 | hutool-all
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | org.projectlombok
70 | lombok
71 | true
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/java/com/zzq/i18n/I18NAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.i18n;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class I18NAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(I18NAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/java/com/zzq/i18n/config/MyLocaleResolver.java:
--------------------------------------------------------------------------------
1 | package com.zzq.i18n.config;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.lang.NonNull;
6 | import org.springframework.lang.Nullable;
7 | import org.springframework.util.StringUtils;
8 | import org.springframework.web.servlet.LocaleResolver;
9 |
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.util.Locale;
13 |
14 |
15 | @Configuration
16 | public class MyLocaleResolver implements LocaleResolver {
17 |
18 | @Autowired
19 | private HttpServletRequest request;
20 |
21 | public Locale getLocal() {
22 | return resolveLocale(request);
23 | }
24 |
25 |
26 | @Override
27 | public Locale resolveLocale(HttpServletRequest httpServletRequest) {
28 | String language = httpServletRequest.getParameter("lang");
29 | Locale locale = Locale.getDefault();
30 | if (!StringUtils.isEmpty(language)){
31 | String[] s = language.split("-");
32 | locale = new Locale(s[0], s[1]);
33 | }
34 | return locale;
35 | }
36 |
37 |
38 | @Override
39 | public void setLocale(@NonNull HttpServletRequest request, @Nullable HttpServletResponse httpServletResponse, @Nullable Locale locale) {
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/java/com/zzq/i18n/ctrl/LangController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.i18n.ctrl;
2 |
3 | import com.zzq.i18n.util.I18nUtil;
4 | import lombok.RequiredArgsConstructor;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | import javax.servlet.http.HttpServletRequest;
9 |
10 | @RestController
11 | @RequiredArgsConstructor
12 | public class LangController {
13 |
14 | @GetMapping("/i18n")
15 | public String i18n(HttpServletRequest request) {
16 | String message1 = I18nUtil.getMessage("A00001", request.getHeader("lang"));
17 | String message2 = I18nUtil.getMessage("A00002", request.getHeader("lang"));
18 | return message1 + message2;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/java/com/zzq/i18n/util/I18nUtil.java:
--------------------------------------------------------------------------------
1 | package com.zzq.i18n.util;
2 |
3 | import com.zzq.i18n.config.MyLocaleResolver;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.context.support.ResourceBundleMessageSource;
8 | import org.springframework.stereotype.Component;
9 | import org.springframework.util.StringUtils;
10 |
11 | import javax.annotation.PostConstruct;
12 | import java.nio.charset.StandardCharsets;
13 | import java.util.Locale;
14 | import java.util.Objects;
15 |
16 | @Slf4j
17 | @Component
18 | public class I18nUtil {
19 |
20 | @Value("${spring.messages.basename}")
21 | private String basename;
22 |
23 | private final MyLocaleResolver resolver;
24 |
25 | private static MyLocaleResolver customLocaleResolver;
26 |
27 | private static String path;
28 |
29 |
30 | public I18nUtil(MyLocaleResolver resolver) {
31 | this.resolver = resolver;
32 | }
33 |
34 |
35 | @PostConstruct
36 | public void init() {
37 | setBasename(basename);
38 | setCustomLocaleResolver(resolver);
39 | }
40 |
41 |
42 | public static String getMessage(String code) {
43 | Locale locale = customLocaleResolver.getLocal();
44 | return getMessage(code, null, code, locale);
45 | }
46 |
47 |
48 | public static String getMessage(String code, String lang) {
49 | Locale locale;
50 | if (StringUtils.isEmpty(lang)) {
51 | locale = Locale.CANADA;
52 | } else {
53 | try {
54 | var split = lang.split("-");
55 | locale = new Locale(split[0], split[1]);
56 | } catch (Exception e) {
57 | locale = Locale.CANADA;
58 | }
59 | }
60 | return getMessage(code, null, code, locale);
61 | }
62 |
63 |
64 |
65 | public static String getStationLetterMessage(String code, String lang) {
66 | Locale locale = null;
67 | if (Objects.equals(lang, "zh-CN")){
68 | locale = Locale.SIMPLIFIED_CHINESE;
69 | }
70 | if (Objects.equals(lang, "en-CA") || Objects.equals(lang, "en-US") ){
71 | locale = Locale.US;
72 | }
73 | if (Objects.equals(lang, "fr-CA")){
74 | locale = Locale.CANADA_FRENCH;
75 | }
76 |
77 |
78 | return getMessage(code, null, code, locale);
79 |
80 | }
81 |
82 |
83 |
84 | public static String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
85 | ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
86 | messageSource.setDefaultEncoding(StandardCharsets.UTF_8.toString());
87 | messageSource.setBasename(path);
88 | String content;
89 | try {
90 | content = messageSource.getMessage(code, args, locale);
91 | } catch (Exception e) {
92 | log.error("i18n error ---> {},{}", e.getMessage(), e);
93 | content = defaultMessage;
94 | }
95 | return content;
96 |
97 | }
98 |
99 | public static void setBasename(String basename) {
100 | I18nUtil.path = basename;
101 | }
102 |
103 | public static void setCustomLocaleResolver(MyLocaleResolver resolver) {
104 | I18nUtil.customLocaleResolver = resolver;
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | spring:
2 | messages:
3 | basename: i18n/messages
4 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/resources/i18n/messages_en_CA.properties:
--------------------------------------------------------------------------------
1 | A00001=Hello World
2 | A00002=Hello JAVA
3 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/resources/i18n/messages_fr_CA.properties:
--------------------------------------------------------------------------------
1 | A00001=Bonjour Monde
2 | A00002=Bonjour JAVA
3 |
--------------------------------------------------------------------------------
/demo-i18n/src/main/resources/i18n/messages_zh_CN.properties:
--------------------------------------------------------------------------------
1 | A00001=你好 世界
2 | A00002=你好 JAVA
3 |
--------------------------------------------------------------------------------
/demo-justauth/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-justauth
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 | me.zhyd.oauth
22 | JustAuth
23 | 1.16.5
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-logging
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-validation
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-web
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-actuator
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-test
50 |
51 |
52 |
53 |
54 | org.mariadb.jdbc
55 | mariadb-java-client
56 | runtime
57 |
58 |
59 |
60 |
61 | cn.hutool
62 | hutool-all
63 |
64 |
65 |
66 | org.projectlombok
67 | lombok
68 | true
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/JustAuthAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | // before Run application, modify application.yaml
7 | @SpringBootApplication
8 | public class JustAuthAppApplication {
9 | public static void main(String[] args) {
10 |
11 | SpringApplication.run(JustAuthAppApplication.class, args);
12 |
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/config/JustAuthConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth.config;
2 |
3 | import cn.hutool.core.date.DatePattern;
4 | import com.fasterxml.jackson.databind.module.SimpleModule;
5 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
6 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
7 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
8 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
9 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
10 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
11 | import com.xkcoding.http.config.HttpConfig;
12 | import com.zzq.justauth.properties.GithubProperties;
13 | import com.zzq.justauth.properties.GoogleProperties;
14 | import com.zzq.justauth.properties.WechatProperties;
15 | import lombok.RequiredArgsConstructor;
16 | import me.zhyd.oauth.config.AuthConfig;
17 | import me.zhyd.oauth.request.AuthGithubRequest;
18 | import me.zhyd.oauth.request.AuthGoogleRequest;
19 | import me.zhyd.oauth.request.AuthRequest;
20 | import me.zhyd.oauth.request.AuthWeChatOpenRequest;
21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
22 | import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
23 | import org.springframework.context.annotation.Bean;
24 | import org.springframework.context.annotation.Configuration;
25 | import org.springframework.context.annotation.Primary;
26 |
27 | import java.net.InetSocketAddress;
28 | import java.net.Proxy;
29 | import java.time.LocalDate;
30 | import java.time.LocalDateTime;
31 | import java.time.LocalTime;
32 |
33 | @Configuration
34 | @RequiredArgsConstructor
35 | public class JustAuthConfig {
36 |
37 | private final GoogleProperties googleProperties;
38 | private final GithubProperties githubProperties;
39 | private final WechatProperties wechatProperties;
40 |
41 | @Bean
42 | @Primary
43 | Jackson2ObjectMapperBuilderCustomizer jacksonCustomer() {
44 |
45 | SimpleModule module = new SimpleModule();
46 |
47 | module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DatePattern.NORM_DATETIME_FORMATTER));
48 | module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DatePattern.NORM_DATETIME_FORMATTER));
49 | module.addSerializer(LocalDate.class, new LocalDateSerializer(DatePattern.NORM_DATE_FORMATTER));
50 | module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DatePattern.NORM_DATE_FORMATTER));
51 | module.addSerializer(LocalTime.class, new LocalTimeSerializer(DatePattern.NORM_TIME_FORMATTER));
52 | module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DatePattern.NORM_TIME_FORMATTER));
53 |
54 | return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.modules(module).build();
55 |
56 | }
57 |
58 |
59 | @Bean(name = "authGoogleRequest")
60 | @ConditionalOnBean(GoogleProperties.class)
61 | public AuthRequest authGoogleRequest() {
62 | return new AuthGoogleRequest(AuthConfig.builder()
63 | .clientId(googleProperties.getClientId())
64 | .clientSecret(googleProperties.getClientSecret())
65 | .redirectUri(googleProperties.getRedirectUri())
66 | .httpConfig(HttpConfig.builder()
67 | .timeout(15000)
68 | .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 10080)))
69 | .build())
70 | .build());
71 | }
72 |
73 |
74 | @Bean("authGithubRequest")
75 | @ConditionalOnBean(GithubProperties.class)
76 | public AuthRequest authGithubRequest() {
77 | return new AuthGithubRequest(AuthConfig.builder()
78 | .clientId(githubProperties.getClientId())
79 | .clientSecret(githubProperties.getClientSecret())
80 | .redirectUri(githubProperties.getRedirectUri())
81 | .build());
82 | }
83 |
84 | @Bean("authWechatRequest")
85 | @ConditionalOnBean(WechatProperties.class)
86 | public AuthRequest authWechatRequest() {
87 | return new AuthWeChatOpenRequest(AuthConfig.builder()
88 | .clientId(wechatProperties.getClientId())
89 | .clientSecret(wechatProperties.getClientSecret())
90 | .redirectUri(wechatProperties.getRedirectUri())
91 | .build());
92 | }
93 |
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/ctrl/GithubLoginController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth.ctrl;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.extern.slf4j.Slf4j;
8 | import me.zhyd.oauth.model.AuthCallback;
9 | import me.zhyd.oauth.model.AuthResponse;
10 | import me.zhyd.oauth.model.AuthToken;
11 | import me.zhyd.oauth.model.AuthUser;
12 | import me.zhyd.oauth.request.AuthRequest;
13 | import me.zhyd.oauth.utils.AuthStateUtils;
14 |
15 | import org.springframework.web.bind.annotation.GetMapping;
16 | import org.springframework.web.bind.annotation.RequestMapping;
17 | import org.springframework.web.bind.annotation.RestController;
18 |
19 | import javax.servlet.http.HttpServletResponse;
20 | import java.io.IOException;
21 | import java.time.LocalDateTime;
22 |
23 | @Slf4j
24 | @RestController
25 | @RequiredArgsConstructor
26 | @RequestMapping("/oauth/github")
27 | public class GithubLoginController {
28 |
29 | private final AuthRequest authGithubRequest;
30 | private final ObjectMapper objectMapper;
31 |
32 | @GetMapping("/login")
33 | public void githubLogin(HttpServletResponse response) throws IOException {
34 | String authorize = authGithubRequest.authorize(AuthStateUtils.createState());
35 | response.sendRedirect(authorize);
36 | }
37 |
38 |
39 | /**
40 | * {
41 | * "code":2000,
42 | * "msg":null,
43 | * "data":{
44 | * "uuid":"",
45 | * "username":"Zhou1998ZQ",
46 | * "nickname":null,
47 | * "avatar":"https://avatars.githubusercontent.com/u/103564579?v=4",
48 | * "blog":"",
49 | * "company":null,
50 | * "location":null,
51 | * "email":null,
52 | * "remark":null,
53 | * "gender":"UNKNOWN",
54 | * "source":"GITHUB",
55 | * "token":{
56 | * "accessToken":"",
57 | * "expireIn":0,
58 | * "refreshToken":null,
59 | * "refreshTokenExpireIn":0,
60 | * "uid":null,
61 | * "openId":null,
62 | * "accessCode":null,
63 | * "unionId":null,
64 | * "scope":null,
65 | * "tokenType":"bearer",
66 | * "idToken":null,
67 | * "macAlgorithm":null,
68 | * "macKey":null,
69 | * "code":null,
70 | * "oauthToken":null,
71 | * "oauthTokenSecret":null,
72 | * "userId":null,
73 | * "screenName":null,
74 | * "oauthCallbackConfirmed":null
75 | * },
76 | * "rawUserInfo":{
77 | * "gists_url":"",
78 | * "repos_url":"",
79 | * "following_url":"",
80 | * "twitter_username":null,
81 | * "bio":null,
82 | * "created_at":"",
83 | * "login":"",
84 | * "type":"",
85 | * "blog":"",
86 | * "subscriptions_url":"",
87 | * "updated_at":"",
88 | * "site_admin":false,
89 | * "company":null,
90 | * "id":103564579,
91 | * "public_repos":1,
92 | * "gravatar_id":"",
93 | * "email":null,
94 | * "organizations_url":"",
95 | * "hireable":null,
96 | * "starred_url":"",
97 | * "followers_url":"",
98 | * "public_gists":0,
99 | * "url":"",
100 | * "received_events_url":"",
101 | * "followers":1,
102 | * "avatar_url":"",
103 | * "events_url":"",
104 | * "html_url":"",
105 | * "following":1,
106 | * "name":null,
107 | * "location":null,
108 | * "node_id":""
109 | * }
110 | * }
111 | * }
112 | *
113 | * @param callback
114 | * @return
115 | */
116 | @RequestMapping("/callback")
117 | public Object login(AuthCallback callback) throws JsonProcessingException {
118 | AuthResponse login = authGithubRequest.login(callback);
119 | if (login.ok()) {
120 | Object data = login.getData();
121 | String json = objectMapper.writeValueAsString(data);
122 | AuthUser authUser = objectMapper.readValue(json, AuthUser.class);
123 | AuthToken token = authUser.getToken();
124 | String accessToken = token.getAccessToken();
125 | JSONObject rawUserInfo = authUser.getRawUserInfo();
126 | LocalDateTime updatedAt = rawUserInfo.getObject("updated_at", LocalDateTime.class);
127 |
128 | log.info("accessToken :" + accessToken);
129 | log.info("updatedAt :" + updatedAt);
130 | log.info("userName :" + authUser.getUsername());
131 | }
132 | return login;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/ctrl/GoogleLoginController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth.ctrl;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.extern.slf4j.Slf4j;
8 | import me.zhyd.oauth.model.AuthCallback;
9 | import me.zhyd.oauth.model.AuthResponse;
10 | import me.zhyd.oauth.model.AuthToken;
11 | import me.zhyd.oauth.model.AuthUser;
12 | import me.zhyd.oauth.request.AuthRequest;
13 | import me.zhyd.oauth.utils.AuthStateUtils;
14 | import org.springframework.web.bind.annotation.GetMapping;
15 | import org.springframework.web.bind.annotation.RequestMapping;
16 | import org.springframework.web.bind.annotation.RestController;
17 |
18 | import javax.servlet.http.HttpServletResponse;
19 | import java.io.IOException;
20 |
21 |
22 | @Slf4j
23 | @RestController
24 | @RequiredArgsConstructor
25 | @RequestMapping("/oauth/google")
26 | public class GoogleLoginController {
27 |
28 |
29 | private final AuthRequest authGoogleRequest;
30 | private final ObjectMapper objectMapper;
31 |
32 | @GetMapping("/login")
33 | public void githubLogin(HttpServletResponse response) throws IOException {
34 | String authorize = authGoogleRequest.authorize(AuthStateUtils.createState());
35 | response.sendRedirect(authorize);
36 | }
37 |
38 |
39 | /**
40 | * {
41 | * "code":2000,
42 | * "data":{
43 | * "avatar":"",
44 | * "email":"",
45 | * "gender":"",
46 | * "location":"",
47 | * "nickname":"",
48 | * "rawUserInfo":{
49 | * "sub":"",
50 | * "email_verified":true,
51 | * "name":"",
52 | * "given_name":"",
53 | * "locale":"",
54 | * "picture":"",
55 | * "email":""
56 | * },
57 | * "source":"GOOGLE",
58 | * "token":{
59 | * "accessToken":"",
60 | * "expireIn":6346,
61 | * "idToken":"",
62 | * "scope":"",
63 | * "tokenType":"Bearer"
64 | * },
65 | * "username":"",
66 | * "uuid":""
67 | * }
68 | * }
69 | *
70 | * @param callback
71 | * @return
72 | */
73 | @RequestMapping("/callback")
74 | public Object login(AuthCallback callback) throws JsonProcessingException {
75 | AuthResponse login = authGoogleRequest.login(callback);
76 | if (login.ok()) {
77 | Object data = login.getData();
78 | String json = objectMapper.writeValueAsString(data);
79 | AuthUser authUser = objectMapper.readValue(json, AuthUser.class);
80 | AuthToken token = authUser.getToken();
81 | String accessToken = token.getAccessToken();
82 | JSONObject rawUserInfo = authUser.getRawUserInfo();
83 | String locale = rawUserInfo.getObject("locale", String.class);
84 |
85 | log.info("accessToken :" + accessToken);
86 | log.info("locale :" + locale);
87 | log.info("userName :" + authUser.getUsername());
88 | }
89 | return login;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/ctrl/WechatLoginController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth.ctrl;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import me.zhyd.oauth.model.AuthCallback;
8 | import me.zhyd.oauth.model.AuthResponse;
9 | import me.zhyd.oauth.model.AuthToken;
10 | import me.zhyd.oauth.model.AuthUser;
11 | import me.zhyd.oauth.request.AuthRequest;
12 | import me.zhyd.oauth.utils.AuthStateUtils;
13 | import org.springframework.web.bind.annotation.GetMapping;
14 | import org.springframework.web.bind.annotation.RequestMapping;
15 | import org.springframework.web.bind.annotation.RestController;
16 |
17 | import javax.servlet.http.HttpServletResponse;
18 | import java.io.IOException;
19 |
20 | @Slf4j
21 | @RestController
22 | @RequiredArgsConstructor
23 | @RequestMapping("/oauth/wechat")
24 | public class WechatLoginController {
25 |
26 | private final AuthRequest authWechatRequest;
27 | private final ObjectMapper objectMapper;
28 |
29 | @GetMapping("/login")
30 | public void githubLogin(HttpServletResponse response) throws IOException {
31 | String authorize = authWechatRequest.authorize(AuthStateUtils.createState());
32 | response.sendRedirect(authorize);
33 | }
34 |
35 |
36 | /**
37 | * {
38 | * "code": 2000,
39 | * "msg": null,
40 | * "data": {
41 | * "uuid": "",
42 | * "username": "",
43 | * "nickname": "",
44 | * "avatar": "",
45 | * "blog": null,
46 | * "company": null,
47 | * "location": "",
48 | * "email": null,
49 | * "remark": null,
50 | * "gender": "",
51 | * "source": "",
52 | * "token": {
53 | * "accessToken": "",
54 | * "expireIn": 4251,
55 | * "refreshToken": "",
56 | * "uid": null,
57 | * "openId": "",
58 | * "accessCode": null,
59 | * "unionId": "",
60 | * "scope": null,
61 | * "tokenType": null,
62 | * "idToken": null,
63 | * "macAlgorithm": null,
64 | * "macKey": null,
65 | * "code": null,
66 | * "oauthToken": null,
67 | * "oauthTokenSecret": null,
68 | * "userId": null,
69 | * "screenName": null,
70 | * "oauthCallbackConfirmed": null
71 | * }* }
72 | * }
73 | *
74 | * @param callback
75 | * @return
76 | */
77 | @RequestMapping("/callback")
78 | public Object login(AuthCallback callback) throws JsonProcessingException {
79 | AuthResponse login = authWechatRequest.login(callback);
80 | if (login.ok()) {
81 | Object data = login.getData();
82 | String json = objectMapper.writeValueAsString(data);
83 | AuthUser authUser = objectMapper.readValue(json, AuthUser.class);
84 | AuthToken token = authUser.getToken();
85 | String accessToken = token.getAccessToken();
86 |
87 | log.info("accessToken :" + accessToken);
88 | log.info("location :" + authUser.getLocation());
89 | log.info("userName :" + authUser.getUsername());
90 | }
91 | return login;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/properties/GithubProperties.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth.properties;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Data
8 | @Component
9 | @ConfigurationProperties(prefix = GithubProperties.PREFIX)
10 | public class GithubProperties {
11 | public static final String PREFIX = "auth.github";
12 |
13 |
14 |
15 | private String clientId;
16 | private String clientSecret;
17 | private String redirectUri;
18 | }
19 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/properties/GoogleProperties.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth.properties;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Data
8 | @Component
9 | @ConfigurationProperties(prefix = GoogleProperties.PREFIX)
10 | public class GoogleProperties {
11 | public static final String PREFIX = "auth.google";
12 |
13 | private String clientId;
14 | private String clientSecret;
15 | private String redirectUri;
16 | }
17 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/java/com/zzq/justauth/properties/WechatProperties.java:
--------------------------------------------------------------------------------
1 | package com.zzq.justauth.properties;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Data
8 | @Component
9 | @ConfigurationProperties(prefix = WechatProperties.PREFIX)
10 | public class WechatProperties {
11 |
12 | public static final String PREFIX = "auth.wechat";
13 |
14 | private String clientId;
15 | private String clientSecret;
16 | private String redirectUri;
17 | }
18 |
--------------------------------------------------------------------------------
/demo-justauth/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 80
3 |
4 | auth:
5 | google:
6 | client-id: 123456789
7 | client-secret: 123456789
8 | redirect-uri: http://i92x88.natappfree.cc/oauth/google/callback
9 |
10 | github:
11 | client-id: 123456789
12 | client-secret: 123456789
13 | redirect-uri: http://i92x88.natappfree.cc/oauth/github/callback
14 |
15 | wechat:
16 | client-id: 123456789
17 | client-secret: 123456789
18 | redirect-uri: http://i92x88.natappfree.cc/oauth/wechat/callback
19 |
20 |
21 |
--------------------------------------------------------------------------------
/demo-limiter/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-requestLimiter
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-aop
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-data-redis
28 |
29 |
30 |
31 | org.apache.commons
32 | commons-pool2
33 |
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-logging
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-validation
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-web
48 |
49 |
50 |
51 |
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-starter-test
56 |
57 |
58 |
59 |
60 | org.mariadb.jdbc
61 | mariadb-java-client
62 | runtime
63 |
64 |
65 |
66 |
67 | cn.hutool
68 | hutool-all
69 |
70 |
71 |
72 |
73 | org.projectlombok
74 | lombok
75 | true
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/LimiterAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class LimiterAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(LimiterAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/annotation/RateLimiter.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * @author zzq
10 | */
11 |
12 | @Target({ElementType.METHOD, ElementType.TYPE})
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface RateLimiter {
15 |
16 | String key() default "rate_limit";
17 |
18 |
19 | int time() default 60;
20 |
21 |
22 | int count() default 100;
23 |
24 | String limitType() default "IP";
25 | }
26 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/aop/RateLimiterAspect.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter.aop;
2 |
3 | import com.zzq.limiter.annotation.RateLimiter;
4 | import com.zzq.limiter.exception.LimiterException;
5 | import com.zzq.limiter.util.IpUtil;
6 | import lombok.RequiredArgsConstructor;
7 | import org.aspectj.lang.JoinPoint;
8 | import org.aspectj.lang.Signature;
9 | import org.aspectj.lang.annotation.Aspect;
10 | import org.aspectj.lang.annotation.Before;
11 | import org.aspectj.lang.annotation.Pointcut;
12 | import org.aspectj.lang.reflect.MethodSignature;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.data.redis.core.RedisTemplate;
16 | import org.springframework.data.redis.core.script.RedisScript;
17 | import org.springframework.http.HttpStatus;
18 | import org.springframework.stereotype.Component;
19 | import org.springframework.web.context.request.RequestAttributes;
20 | import org.springframework.web.context.request.RequestContextHolder;
21 |
22 | import javax.servlet.http.HttpServletRequest;
23 | import java.lang.reflect.Method;
24 | import java.util.Collections;
25 | import java.util.List;
26 | import java.util.Objects;
27 |
28 | @Aspect
29 | @Component
30 | @RequiredArgsConstructor
31 | public class RateLimiterAspect {
32 | private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
33 |
34 | private final RedisTemplate redisTemplate;
35 |
36 | private final RedisScript limitScript;
37 |
38 | @Pointcut("@annotation(com.zzq.limiter.annotation.RateLimiter)")
39 | public void rateLimiterPointCut() {
40 | }
41 |
42 | @Before("rateLimiterPointCut()")
43 | public void doBefore(JoinPoint point) {
44 | try {
45 | Signature signature = point.getSignature();
46 | MethodSignature methodSignature = (MethodSignature) signature;
47 | RateLimiter rateLimiter = methodSignature.getMethod().getAnnotation(RateLimiter.class);
48 | String key = rateLimiter.key();
49 | int time = rateLimiter.time();
50 | int count = rateLimiter.count();
51 |
52 | String combineKey = getCombineKey(rateLimiter, point);
53 | List keys = Collections.singletonList(combineKey);
54 |
55 | Long number = redisTemplate.execute(limitScript, keys, count, time);
56 | if (Objects.isNull(number) || number.intValue() > count) {
57 | throw new LimiterException(HttpStatus.TOO_MANY_REQUESTS, "too many requests");
58 | }
59 | log.info("limiter request'{}',current request'{}',cache key'{}'", count, number.intValue(), key);
60 | } catch (Exception e) {
61 | if (e instanceof LimiterException) {
62 | throw e;
63 | }
64 | throw new RuntimeException("server limiter error", e);
65 | }
66 | }
67 |
68 |
69 | public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
70 | StringBuilder stringBuffer = new StringBuilder(rateLimiter.key());
71 | if ("IP".equals(rateLimiter.limitType())) {
72 | RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
73 | if (requestAttributes != null) {
74 | HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
75 | stringBuffer.append(IpUtil.getIpAddr(request));
76 | }
77 |
78 | }
79 | MethodSignature signature = (MethodSignature) point.getSignature();
80 | Method method = signature.getMethod();
81 | Class> targetClass = method.getDeclaringClass();
82 | stringBuffer.append("-").append(targetClass.getName()).append("- ").append(method.getName());
83 | return stringBuffer.toString();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter.config;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.PropertyAccessor;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.data.redis.connection.RedisConnectionFactory;
10 | import org.springframework.data.redis.core.RedisTemplate;
11 | import org.springframework.data.redis.core.script.DefaultRedisScript;
12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
13 |
14 | @Configuration
15 | public class RedisConfig {
16 |
17 | @Bean
18 | public DefaultRedisScript limitScript() {
19 | DefaultRedisScript redisScript = new DefaultRedisScript<>();
20 | redisScript.setScriptText(limitScriptText());
21 | redisScript.setResultType(Long.class);
22 | return redisScript;
23 | }
24 |
25 | /**
26 | * limitScriptText
27 | */
28 | private String limitScriptText() {
29 | return "local key = KEYS[1]\n" +
30 | "local count = tonumber(ARGV[1])\n" +
31 | "local time = tonumber(ARGV[2])\n" +
32 | "local current = redis.call('get', key);\n" +
33 | "if current and tonumber(current) > count then\n" +
34 | " return current;\n" +
35 | "end\n" +
36 | "current = redis.call('incr', key)\n" +
37 | "if tonumber(current) == 1 then\n" +
38 | " redis.call('expire', key, time)\n" +
39 | "end\n" +
40 | "return current;";
41 | }
42 |
43 |
44 | @Bean
45 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
46 | RedisTemplate template = new RedisTemplate<>();
47 | template.setConnectionFactory(factory);
48 |
49 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
50 | ObjectMapper om = new ObjectMapper();
51 |
52 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
53 |
54 |
55 | om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
56 | jackson2JsonRedisSerializer.setObjectMapper(om);
57 |
58 |
59 | template.setKeySerializer(jackson2JsonRedisSerializer);
60 | template.setHashKeySerializer(jackson2JsonRedisSerializer);
61 |
62 | template.setValueSerializer(jackson2JsonRedisSerializer);
63 | template.setHashValueSerializer(jackson2JsonRedisSerializer);
64 | template.afterPropertiesSet();
65 |
66 | return template;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/ctrl/LimiterController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter.ctrl;
2 |
3 | import com.zzq.limiter.annotation.RateLimiter;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RestController;
6 |
7 | @RestController
8 | public class LimiterController {
9 |
10 |
11 | @GetMapping
12 | @RateLimiter(time = 1,count = 1)
13 | public String test(){
14 | return "hello";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/exception/LimiterException.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter.exception;
2 |
3 | import lombok.Getter;
4 | import org.springframework.http.HttpStatus;
5 |
6 | public class LimiterException extends RuntimeException {
7 |
8 | @Getter
9 | private final HttpStatus status;
10 |
11 | public LimiterException(HttpStatus status, String message, Throwable cause) {
12 | super(message, cause);
13 | this.status = status;
14 | }
15 |
16 | public LimiterException(HttpStatus status, String message) {
17 | super(message);
18 | this.status = status;
19 | }
20 |
21 | public void throwIfNot(Boolean b) {
22 | if (!Boolean.TRUE.equals(b))
23 | throw this;
24 | }
25 |
26 | public void throwIf(Boolean b) {
27 | if (Boolean.TRUE.equals(b))
28 | throw this;
29 | }
30 |
31 | public void throwIt() {
32 | this.throwIfNot(false);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/handler/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter.handler;
2 |
3 | import com.zzq.limiter.exception.LimiterException;
4 | import org.springframework.web.bind.annotation.ExceptionHandler;
5 | import org.springframework.web.bind.annotation.RestControllerAdvice;
6 |
7 | @RestControllerAdvice(basePackages = "com.zzq.limiter")
8 | public class GlobalExceptionHandler {
9 |
10 | @ExceptionHandler(LimiterException.class)
11 | public String limiterExceptionHandler(LimiterException exception) {
12 | return exception.getMessage();
13 | }
14 |
15 |
16 | @ExceptionHandler(Exception.class)
17 | public String exceptionHandle(Exception exception) {
18 | return exception.getMessage();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/java/com/zzq/limiter/util/IpUtil.java:
--------------------------------------------------------------------------------
1 | package com.zzq.limiter.util;
2 |
3 | import javax.servlet.http.HttpServletRequest;
4 | import java.net.InetAddress;
5 | import java.net.UnknownHostException;
6 |
7 | public class IpUtil {
8 | public static String getIpAddr(HttpServletRequest request) {
9 | String ipAddress;
10 | try {
11 | ipAddress = request.getHeader("x-forwarded-for");
12 | if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
13 | ipAddress = request.getHeader("Proxy-Client-IP");
14 | }
15 | if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
16 | ipAddress = request.getHeader("WL-Proxy-Client-IP");
17 | }
18 | if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
19 | ipAddress = request.getRemoteAddr();
20 | if ("127.0.0.1".equals(ipAddress)) {
21 | // 根据网卡取本机配置的IP
22 | InetAddress inet = null;
23 | try {
24 | inet = InetAddress.getLocalHost();
25 | } catch (UnknownHostException e) {
26 | e.printStackTrace();
27 | }
28 | ipAddress = inet.getHostAddress();
29 | }
30 | }
31 |
32 | if (ipAddress != null && ipAddress.length() > 15) {
33 | // = 15
34 | if (ipAddress.indexOf(",") > 0) {
35 | ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
36 | }
37 | }
38 | } catch (Exception e) {
39 | ipAddress="";
40 | }
41 |
42 |
43 | return ipAddress;
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/demo-limiter/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 |
2 | spring:
3 | redis:
4 | host: localhost
5 | port: 6379
6 | username:
7 | password:
8 | database: 0
9 | client-type: lettuce
10 | lettuce:
11 | pool:
12 | enabled: true
13 | max-idle: 4
14 | min-idle: 2
15 | max-active: 8
16 |
17 |
18 |
--------------------------------------------------------------------------------
/demo-multithreading/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-multithreading
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-logging
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-validation
31 |
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-web
36 |
37 |
38 |
39 |
40 | com.github.oshi
41 | oshi-core
42 | ${oshi.version}
43 | runtime
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-test
50 |
51 |
52 |
53 |
54 | org.mariadb.jdbc
55 | mariadb-java-client
56 | runtime
57 |
58 |
59 |
60 |
61 | cn.hutool
62 | hutool-all
63 |
64 |
65 |
66 |
67 | org.projectlombok
68 | lombok
69 | true
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/java/com/zzq/multithreading/MultiThreadingAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.multithreading;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class MultiThreadingAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(MultiThreadingAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/java/com/zzq/multithreading/call/AsyncServiceCall.java:
--------------------------------------------------------------------------------
1 | package com.zzq.multithreading.call;
2 |
3 | import org.springframework.scheduling.annotation.Async;
4 |
5 | import java.util.concurrent.Callable;
6 |
7 |
8 | public class AsyncServiceCall implements Callable {
9 |
10 | @Override
11 | public String call() throws Exception {
12 | return Thread.currentThread().getName();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/java/com/zzq/multithreading/config/ExecutorConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.multithreading.config;
2 |
3 | import cn.hutool.core.thread.ExecutorBuilder;
4 | import cn.hutool.core.thread.NamedThreadFactory;
5 | import cn.hutool.system.oshi.OshiUtil;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
10 |
11 | import java.util.concurrent.Executor;
12 | import java.util.concurrent.ExecutorService;
13 | import java.util.concurrent.LinkedBlockingQueue;
14 |
15 |
16 | @Configuration
17 | @Slf4j
18 | public class ExecutorConfig {
19 |
20 | @Bean()
21 | ExecutorService executorService() {
22 | int cpuCoreNum = 4;
23 | try {
24 | cpuCoreNum = OshiUtil.getCpuInfo().getCpuNum();
25 | } catch (Throwable e) {
26 | log.warn("cpu core num error, {}", e.getMessage(), e);
27 | }
28 |
29 | return ExecutorBuilder.create()
30 | .setCorePoolSize(cpuCoreNum)
31 | .setMaxPoolSize(cpuCoreNum * 2 + 1)
32 | .setWorkQueue(new LinkedBlockingQueue<>(cpuCoreNum * 16))
33 | .setThreadFactory(new NamedThreadFactory("CE", false))
34 | .build();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/java/com/zzq/multithreading/ctrl/AsyncController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.multithreading.ctrl;
2 |
3 | import com.zzq.multithreading.service.AsyncService;
4 | import lombok.RequiredArgsConstructor;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | @RestController
9 | @RequiredArgsConstructor
10 | public class AsyncController {
11 | private final AsyncService asyncService;
12 |
13 | @GetMapping("/async")
14 | public String async() {
15 | asyncService.executeAsync();
16 | return Thread.currentThread().getName();
17 | }
18 |
19 | @GetMapping("/completableFuture")
20 | public String completableFuture() {
21 | asyncService.completableFuture();
22 | return Thread.currentThread().getName();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/java/com/zzq/multithreading/run/AsyncServiceRun.java:
--------------------------------------------------------------------------------
1 | package com.zzq.multithreading.run;
2 |
3 | import lombok.SneakyThrows;
4 | import lombok.extern.slf4j.Slf4j;
5 |
6 | @Slf4j
7 | public class AsyncServiceRun implements Runnable {
8 |
9 | @SneakyThrows
10 | @Override
11 | public void run() {
12 | Thread.sleep(3000);
13 | String name = Thread.currentThread().getName();
14 | log.info("run -------> {}", name);
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/java/com/zzq/multithreading/service/AsyncService.java:
--------------------------------------------------------------------------------
1 | package com.zzq.multithreading.service;
2 |
3 | import java.util.concurrent.ExecutionException;
4 |
5 | public interface AsyncService {
6 | void executeAsync();
7 |
8 | void completableFuture();
9 | }
10 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/java/com/zzq/multithreading/service/impl/AsyncServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzq.multithreading.service.impl;
2 |
3 | import com.zzq.multithreading.call.AsyncServiceCall;
4 | import com.zzq.multithreading.run.AsyncServiceRun;
5 | import com.zzq.multithreading.service.AsyncService;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.stereotype.Service;
9 |
10 |
11 | import java.util.concurrent.CompletableFuture;
12 | import java.util.concurrent.ExecutionException;
13 | import java.util.concurrent.ExecutorService;
14 | import java.util.concurrent.Future;
15 |
16 | @Service
17 | @RequiredArgsConstructor
18 | @Slf4j
19 | public class AsyncServiceImpl implements AsyncService {
20 | private final ExecutorService executorService;
21 |
22 |
23 | @Override
24 | public void executeAsync() {
25 |
26 | executorService.execute(new AsyncServiceRun());
27 |
28 | Future> submit = executorService.submit(new AsyncServiceCall());
29 | try {
30 | Object name = submit.get();
31 | log.info("call -------> {}", name);
32 | } catch (InterruptedException | ExecutionException e) {
33 | e.printStackTrace();
34 | }
35 |
36 |
37 | }
38 |
39 |
40 | @Override
41 | public void completableFuture() {
42 | try {
43 | // same as executeAsync.submit() , CompletableFuture.runAsync no return value
44 | CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> {
45 | try {
46 | Thread.sleep(2000);
47 | log.info("completableFuture -------> {}", Thread.currentThread().getName());
48 | } catch (Exception e) {
49 | e.printStackTrace();
50 | }
51 | return 1d;
52 | }, executorService);
53 |
54 | // when completableFuture is done, then call thenApplyAsync
55 | CompletableFuture doubleCompletableFuture0 = completableFuture.thenApplyAsync(num -> {
56 | try {
57 | Thread.sleep(5000);
58 | } catch (InterruptedException e) {
59 | e.printStackTrace();
60 | }
61 | log.info("doubleCompletableFuture0 -------> {}", Thread.currentThread().getName());
62 | return num * 2;
63 | }
64 | , executorService);
65 |
66 | // when completableFuture is done, then call thenApplyAsync
67 | CompletableFuture doubleCompletableFuture1 = completableFuture.thenApplyAsync(num -> {
68 | try {
69 | Thread.sleep(5000);
70 | } catch (InterruptedException e) {
71 | e.printStackTrace();
72 | }
73 | log.info("doubleCompletableFuture1 -------> {}", Thread.currentThread().getName());
74 | return num * 3;
75 | }, executorService);
76 |
77 | // when completableFuture is done, then call runAsync
78 | CompletableFuture.runAsync(() -> {
79 | System.out.println("runAsync -------> " + Thread.currentThread().getName());
80 | }, executorService);
81 |
82 |
83 | CompletableFuture.allOf(doubleCompletableFuture0, doubleCompletableFuture1).get();
84 | Double d1 = doubleCompletableFuture0.get();
85 | Double d2 = doubleCompletableFuture1.get();
86 | log.info("aDouble -------> {}", d1 + d2);
87 | } catch (InterruptedException | ExecutionException e) {
88 | e.printStackTrace();
89 | }
90 | }
91 | }
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/demo-multithreading/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhou1998ZQ/springboot-summary/0472bd7546604d231b54a696c2848dcd08226d68/demo-multithreading/src/main/resources/application.yaml
--------------------------------------------------------------------------------
/demo-multithreading/src/main/resources/static/upload/a.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhou1998ZQ/springboot-summary/0472bd7546604d231b54a696c2848dcd08226d68/demo-multithreading/src/main/resources/static/upload/a.pdf
--------------------------------------------------------------------------------
/demo-poi/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-poi
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 | org.apache.poi
23 | poi
24 |
25 |
26 |
27 | org.apache.poi
28 | poi-ooxml
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-logging
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-validation
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-web
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-actuator
49 |
50 |
51 |
52 |
53 | org.springframework.boot
54 | spring-boot-starter-test
55 |
56 |
57 |
58 |
59 | org.mariadb.jdbc
60 | mariadb-java-client
61 | runtime
62 |
63 |
64 |
65 |
66 | cn.hutool
67 | hutool-all
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | org.projectlombok
81 | lombok
82 | true
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/demo-poi/src/main/java/com/zzq/poi/PoiAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.poi;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class PoiAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(PoiAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-poi/src/main/java/com/zzq/poi/ctrl/PoiController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.poi.ctrl;
2 |
3 | import com.zzq.poi.service.PoiService;
4 | import lombok.RequiredArgsConstructor;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.PostMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 | import org.springframework.web.multipart.MultipartFile;
9 |
10 | @RestController
11 | @RequiredArgsConstructor
12 | public class PoiController {
13 |
14 | private final PoiService poiService;
15 |
16 | @PostMapping("/read")
17 | public Object read(MultipartFile file) {
18 |
19 | return poiService.read(file);
20 | }
21 |
22 | @GetMapping("/download")
23 | public void download() {
24 | poiService.download();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo-poi/src/main/java/com/zzq/poi/pojo/User.java:
--------------------------------------------------------------------------------
1 | package com.zzq.poi.pojo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | @Data
7 | @AllArgsConstructor
8 | public class User {
9 |
10 | private String username;
11 | private String password;
12 | }
13 |
--------------------------------------------------------------------------------
/demo-poi/src/main/java/com/zzq/poi/service/PoiService.java:
--------------------------------------------------------------------------------
1 | package com.zzq.poi.service;
2 |
3 | import org.springframework.web.multipart.MultipartFile;
4 |
5 |
6 |
7 | public interface PoiService {
8 | Object read(MultipartFile file);
9 |
10 | void download();
11 | }
12 |
--------------------------------------------------------------------------------
/demo-poi/src/main/java/com/zzq/poi/service/impl/PoiServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzq.poi.service.impl;
2 |
3 | import com.zzq.poi.pojo.User;
4 | import com.zzq.poi.service.PoiService;
5 | import org.apache.poi.hssf.usermodel.*;
6 | import org.apache.poi.ss.usermodel.Cell;
7 | import org.apache.poi.ss.usermodel.Row;
8 | import org.apache.poi.ss.usermodel.Sheet;
9 | import org.apache.poi.ss.usermodel.Workbook;
10 | import org.apache.poi.xssf.usermodel.XSSFWorkbook;
11 | import org.springframework.stereotype.Service;
12 | import org.springframework.web.context.request.RequestAttributes;
13 | import org.springframework.web.context.request.RequestContextHolder;
14 | import org.springframework.web.context.request.ServletRequestAttributes;
15 | import org.springframework.web.multipart.MultipartFile;
16 |
17 | import javax.servlet.http.HttpServletRequest;
18 | import javax.servlet.http.HttpServletResponse;
19 | import java.io.FileNotFoundException;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.io.OutputStream;
23 | import java.net.URLEncoder;
24 | import java.nio.charset.StandardCharsets;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 | import java.util.Objects;
28 |
29 | @Service
30 | public class PoiServiceImpl implements PoiService {
31 | private static final String XLS_TYPE = ".xls";
32 | private static final String XLSX_TYPE = ".xlsx";
33 |
34 | @Override
35 | public Object read(MultipartFile file) {
36 |
37 | try {
38 | checkFile(file);
39 | Workbook workbook = getWorkBook(file);
40 |
41 | List list = new ArrayList<>();
42 |
43 | if (workbook != null) {
44 | for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
45 |
46 | Sheet sheet = workbook.getSheetAt(sheetNum);
47 | if (sheet == null) {
48 | continue;
49 | }
50 |
51 | int firstRowNum = sheet.getFirstRowNum();
52 | int lastRowNum = sheet.getLastRowNum();
53 |
54 | for (int rowNum = firstRowNum + 1; rowNum <= lastRowNum; rowNum++) {
55 | // currentRow
56 | Row row = sheet.getRow(rowNum);
57 | if (row == null) {
58 | continue;
59 | }
60 |
61 | int firstCellNum = row.getFirstCellNum();
62 | int lastCellNum = row.getLastCellNum();
63 |
64 | String[] cells = new String[row.getLastCellNum()];
65 | // for loop currentRow
66 | for (int cellNum = firstCellNum; cellNum < lastCellNum; cellNum++) {
67 | Cell cell = row.getCell(cellNum, Row.RETURN_BLANK_AS_NULL);
68 | cells[cellNum] = getCellValue(cell);
69 | }
70 | list.add(cells);
71 | }
72 | }
73 | }
74 | return list;
75 | } catch (Exception e) {
76 | e.printStackTrace();
77 | }
78 | return List.of();
79 | }
80 |
81 | @Override
82 | public void download() {
83 | try {
84 | List userList = new ArrayList<>();
85 | userList.add(new User("zzq", "123456"));
86 | userList.add(new User("dmx", "678910"));
87 |
88 | String[] headers = {"username", "password"};
89 | // type
90 | HSSFWorkbook workbook = new HSSFWorkbook();
91 | HSSFSheet sheet = workbook.createSheet();
92 | // set width
93 | sheet.setDefaultColumnWidth(20);
94 | HSSFRow row = sheet.createRow(0);
95 | // first row
96 | for (int i = 0; i < headers.length; i++) {
97 | HSSFCell cell = row.createCell(i);
98 | HSSFRichTextString text = new HSSFRichTextString(headers[i]);
99 |
100 | cell.setCellValue(text);
101 | }
102 |
103 | for (int i = 0; i < userList.size(); i++) {
104 | User user = userList.get(i);
105 | // second row
106 | row = sheet.createRow(i + 1);
107 | row.createCell(0).setCellValue(user.getUsername());
108 | row.createCell(1).setCellValue(user.getPassword());
109 | }
110 |
111 | String fileName = "test.xlsx";
112 | HttpServletResponse response =
113 | ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
114 | RequestAttributes resetAttributes = RequestContextHolder.currentRequestAttributes();
115 | HttpServletRequest request = ((ServletRequestAttributes) resetAttributes).getRequest();
116 |
117 | final String userAgent = request.getHeader("USER-AGENT");
118 |
119 | if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
120 | // IE
121 | fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
122 | } else if (userAgent.contains("Mozilla")) {
123 | // google,firefox
124 | fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1");
125 | } else {
126 | // other
127 | fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
128 | }
129 |
130 |
131 | response.reset();
132 |
133 | response.setContentType("application/octet-stream");
134 | response.addHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
135 | OutputStream os = response.getOutputStream();
136 | workbook.write(os);
137 | os.close();
138 | } catch (Exception e) {
139 | e.printStackTrace();
140 | }
141 |
142 | }
143 |
144 | public static void checkFile(MultipartFile file) throws IOException {
145 |
146 | if (null == file) {
147 | throw new FileNotFoundException("file is not exist!");
148 | }
149 |
150 | String fileName = file.getOriginalFilename();
151 |
152 | if (!fileName.endsWith(XLS_TYPE) && !fileName.endsWith(XLSX_TYPE)) {
153 | throw new IOException(fileName + "is not excel file!");
154 | }
155 | }
156 |
157 | public static Workbook getWorkBook(MultipartFile file) {
158 |
159 | String fileName = file.getOriginalFilename();
160 |
161 | Workbook workbook = null;
162 | try {
163 | InputStream is = file.getInputStream();
164 |
165 | if (fileName.endsWith(XLS_TYPE)) {
166 | // 2003
167 | workbook = new HSSFWorkbook(is);
168 | } else if (fileName.endsWith(XLSX_TYPE)) {
169 | // 2007
170 | workbook = new XSSFWorkbook(is);
171 | }
172 | } catch (IOException e) {
173 | e.printStackTrace();
174 | }
175 | return workbook;
176 | }
177 |
178 |
179 | public static String getCellValue(Cell cell) {
180 | String cellValue = "";
181 | if (cell == null) {
182 | return cellValue;
183 | }
184 | // numeric to string
185 | if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
186 | cell.setCellType(Cell.CELL_TYPE_STRING);
187 | }
188 | // check type
189 | switch (cell.getCellType()) {
190 |
191 | case Cell.CELL_TYPE_NUMERIC:
192 | cellValue = String.valueOf(cell.getNumericCellValue());
193 | break;
194 |
195 | case Cell.CELL_TYPE_STRING:
196 | cellValue = String.valueOf(cell.getStringCellValue());
197 | break;
198 |
199 | case Cell.CELL_TYPE_BOOLEAN:
200 | cellValue = String.valueOf(cell.getBooleanCellValue());
201 | break;
202 |
203 | case Cell.CELL_TYPE_FORMULA:
204 | cellValue = String.valueOf(cell.getCellFormula());
205 | break;
206 |
207 | case Cell.CELL_TYPE_BLANK:
208 | cellValue = "";
209 | break;
210 |
211 | case Cell.CELL_TYPE_ERROR:
212 | cellValue = "Illegal character";
213 | break;
214 | default:
215 | cellValue = "unknown type";
216 | break;
217 | }
218 | return cellValue;
219 | }
220 |
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/demo-poi/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Zhou1998ZQ/springboot-summary/0472bd7546604d231b54a696c2848dcd08226d68/demo-poi/src/main/resources/application.yaml
--------------------------------------------------------------------------------
/demo-quartz/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-quartz
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-quartz
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-logging
31 |
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-validation
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-web
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-actuator
46 |
47 |
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-starter-test
52 |
53 |
54 |
55 |
56 | org.mariadb.jdbc
57 | mariadb-java-client
58 | runtime
59 |
60 |
61 |
62 |
63 | cn.hutool
64 | hutool-all
65 |
66 |
67 |
68 | org.mybatis.spring.boot
69 | mybatis-spring-boot-starter
70 |
71 |
72 | com.baomidou
73 | mybatis-plus-boot-starter
74 |
75 |
76 |
77 | org.projectlombok
78 | lombok
79 | true
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/demo-quartz/src/main/java/com/zzq/quartz/QuartzAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.quartz;
2 |
3 |
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.scheduling.annotation.EnableScheduling;
7 |
8 | /**
9 | * Scheduled : easy to schedule task
10 | * Quartz : distributed task scheduler
11 | */
12 |
13 | @EnableScheduling
14 | @SpringBootApplication
15 | public class QuartzAppApplication {
16 | public static void main(String[] args) {
17 |
18 | SpringApplication.run(QuartzAppApplication.class, args);
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/demo-quartz/src/main/java/com/zzq/quartz/config/QuartzConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.quartz.config;
2 |
3 | import com.zzq.quartz.job.FirstJob;
4 | import org.quartz.*;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | @Configuration
9 | public class QuartzConfig {
10 |
11 | public static final String JOB_DETAIL_IDENTITY = "DateTimeJob";
12 |
13 | @Bean
14 | public JobDetail printTimeJobDetail() {
15 | return JobBuilder.newJob(FirstJob.class)
16 | .withIdentity(JOB_DETAIL_IDENTITY)
17 | .storeDurably()
18 | .build();
19 | }
20 |
21 |
22 | @Bean
23 | public Trigger printTimeJobTrigger() {
24 | //SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever();
25 | CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0 0/1 * * * ?");
26 | return TriggerBuilder.newTrigger()
27 | .forJob(printTimeJobDetail())
28 | .withSchedule(cronScheduleBuilder)
29 | .build();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/demo-quartz/src/main/java/com/zzq/quartz/job/FirstJob.java:
--------------------------------------------------------------------------------
1 | package com.zzq.quartz.job;
2 |
3 | import cn.hutool.core.date.LocalDateTimeUtil;
4 | import cn.hutool.core.util.StrUtil;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.quartz.JobExecutionContext;
7 | import org.quartz.JobExecutionException;
8 | import org.springframework.scheduling.quartz.QuartzJobBean;
9 | import org.springframework.transaction.annotation.Transactional;
10 |
11 | @Slf4j
12 | public class FirstJob extends QuartzJobBean {
13 |
14 |
15 | @Override
16 | @Transactional(rollbackFor = Exception.class)
17 | protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
18 | //business logic code here
19 | log.info(StrUtil.format("FirstJob executeInternal , current time : {}", LocalDateTimeUtil.now()));
20 | }
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/demo-quartz/src/main/java/com/zzq/quartz/scheduled/AnnotationScheduled.java:
--------------------------------------------------------------------------------
1 | package com.zzq.quartz.scheduled;
2 |
3 | import cn.hutool.core.date.LocalDateTimeUtil;
4 | import cn.hutool.core.util.StrUtil;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | import org.springframework.scheduling.annotation.Scheduled;
8 | import org.springframework.stereotype.Component;
9 |
10 | /**
11 | * @see ...
12 | */
13 | @Slf4j
14 | @Component
15 | public class AnnotationScheduled {
16 |
17 | // every 2 minutes
18 |
19 | @Scheduled(cron = "0 0/2 * * * ?")
20 | public void printTime() {
21 | log.info(StrUtil.format("AnnotationScheduled , current time : {}", LocalDateTimeUtil.now()));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/demo-quartz/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | spring:
2 | datasource:
3 | url: jdbc:mariadb://localhost:3306/springboot-summary
4 | username: root
5 | password: root
6 | hikari:
7 | pool-name: HikariCP
8 | connection-timeout: 3000
9 | connection-test-query: SELECT 1
10 | maximum-pool-size: 64
11 | minimum-idle: 4
12 | idle-timeout: 180000
13 | max-lifetime: 1800000
14 |
15 | quartz:
16 | job-store-type: jdbc
17 | auto-startup: true
18 | startup-delay: 2s
19 | wait-for-jobs-to-complete-on-shutdown: true
20 | overwrite-existing-jobs: true
21 | jdbc:
22 | initialize-schema: always
23 |
24 | properties:
25 | org:
26 | quartz:
27 | scheduler:
28 | instanceName: BC # backend cluster
29 | instanceId: AUTO
30 | jobStore:
31 | useProperties: false
32 | tablePrefix: QRTZ_
33 | isClustered: true
34 | clusterCheckinInterval: 10000
35 | threadPool:
36 | class: org.quartz.simpl.SimpleThreadPool
37 | threadCount: 2
38 | threadPriority: 5
39 |
40 |
--------------------------------------------------------------------------------
/demo-rabbitmq/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-rabbitmq
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-amqp
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-logging
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-validation
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-web
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-actuator
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-test
50 |
51 |
52 |
53 |
54 | org.mariadb.jdbc
55 | mariadb-java-client
56 | runtime
57 |
58 |
59 |
60 |
61 | cn.hutool
62 | hutool-all
63 |
64 |
65 |
66 | org.projectlombok
67 | lombok
68 | true
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/demo-rabbitmq/src/main/java/com/zzq/rabbitmq/RabbitMqAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.rabbitmq;
2 |
3 |
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 |
8 | @SpringBootApplication
9 | public class RabbitMqAppApplication {
10 | public static void main(String[] args) {
11 |
12 | SpringApplication.run(RabbitMqAppApplication.class, args);
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo-rabbitmq/src/main/java/com/zzq/rabbitmq/amqp/ConsumerWorker.java:
--------------------------------------------------------------------------------
1 | package com.zzq.rabbitmq.amqp;
2 |
3 | import cn.hutool.core.convert.Convert;
4 | import cn.hutool.core.date.LocalDateTimeUtil;
5 | import cn.hutool.core.util.StrUtil;
6 | import com.rabbitmq.client.Channel;
7 | import com.zzq.rabbitmq.config.AmqpConfig;
8 | import lombok.RequiredArgsConstructor;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.amqp.core.AmqpTemplate;
11 | import org.springframework.amqp.core.Message;
12 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
13 | import org.springframework.stereotype.Component;
14 |
15 | import java.io.IOException;
16 |
17 | @Component
18 | @Slf4j
19 | @RequiredArgsConstructor
20 | public class ConsumerWorker {
21 |
22 | private final AmqpTemplate amqpTemplate;
23 |
24 | /**
25 | * retry 3 times
26 | */
27 | @RabbitListener(queues = AmqpConfig.QUEUE_FIRST)
28 | public void receiveQ1(String data, Message message) {
29 | try {
30 | //business logic code here
31 | log.info(StrUtil.format("consume info {}", data));
32 | //int c = 10 / 0;
33 | } catch (Exception e) {
34 | Integer retry = Convert.toInt(message.getMessageProperties().getHeader("retry"), 0);
35 | if (retry < 3) {
36 | log.info(StrUtil.format("consume info {} ,retry times :", data, retry), e);
37 | amqpTemplate.convertAndSend(AmqpConfig.QUEUE_FIRST, data, msg -> {
38 | msg.getMessageProperties().setHeader("retry", retry + 1);
39 | return msg;
40 | });
41 | }
42 | }
43 |
44 | }
45 |
46 |
47 | /**
48 | * manual ack
49 | */
50 | @RabbitListener(queues = AmqpConfig.QUEUE_SECOND)
51 | public void receiveQ2(String data, Channel channel, Message message) throws IOException {
52 | try {
53 | //business logic code here
54 | log.warn(StrUtil.format("consume warning {}", data));
55 | //int c = 10 / 0;
56 |
57 | channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
58 | } catch (Exception e) {
59 | log.warn(StrUtil.format("consume warning retrying {}", data));
60 | //basicNack(long deliveryTag, boolean multiple, boolean requeue)
61 | channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
62 | }
63 |
64 | }
65 |
66 | /**
67 | * delay message
68 | */
69 | @RabbitListener(queues = AmqpConfig.QUEUE_THIRD)
70 | public void receiveQ3(String data) {
71 | //business logic code here
72 | log.error(StrUtil.format("consume error {}, current time {}", data, LocalDateTimeUtil.now()));
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/demo-rabbitmq/src/main/java/com/zzq/rabbitmq/config/AmqpConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.rabbitmq.config;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.springframework.amqp.core.*;
5 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
6 | import org.springframework.amqp.support.converter.MessageConverter;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 | import java.util.Map;
11 |
12 | @Configuration
13 | public class AmqpConfig {
14 |
15 | public static final String QUEUE_FIRST = "queue.first";
16 | public static final String QUEUE_SECOND = "queue.second";
17 | public static final String QUEUE_THIRD = "queue.third";
18 | public static final String EXCHANGE_FIRST = "exchange.first";
19 |
20 | public static final String QUEUE_DELAY = "queue.delay";
21 | public static final String EXCHANGE_DELAY = "exchange.delay";
22 | public static final String ROUTING_DELAY = "routing.delay";
23 |
24 | public final static String ROUTING_KEY_WARNING = "warning";
25 | public final static String ROUTING_KEY_INFO = "info";
26 | public final static String ROUTING_KEY_ERROR = "error";
27 |
28 |
29 | @Bean
30 | MessageConverter messageConverter(ObjectMapper objectMapper) {
31 | return new Jackson2JsonMessageConverter(objectMapper);
32 | }
33 |
34 |
35 | @Bean
36 | public Queue queueFirst() {
37 | return QueueBuilder
38 | .durable(QUEUE_FIRST)
39 | .build();
40 | }
41 |
42 | @Bean
43 | public Queue queueSecond() {
44 | return QueueBuilder
45 | .durable(QUEUE_SECOND)
46 | .build();
47 | }
48 |
49 | @Bean
50 | public Queue queueThird() {
51 | return QueueBuilder
52 | .durable(QUEUE_THIRD)
53 | .build();
54 | }
55 |
56 | @Bean
57 | public Queue queueDelay() {
58 | return QueueBuilder
59 | .durable(QUEUE_DELAY)
60 | .withArguments(Map.of("x-dead-letter-exchange", EXCHANGE_FIRST, "x-dead-letter-routing-key", ROUTING_KEY_ERROR))
61 | .build();
62 | }
63 |
64 | @Bean
65 | public Exchange exchange() {
66 | return ExchangeBuilder.directExchange(EXCHANGE_FIRST).build();
67 | }
68 |
69 |
70 | @Bean
71 | public Exchange delayExchange() {
72 | return ExchangeBuilder.directExchange(EXCHANGE_DELAY).build();
73 | }
74 |
75 |
76 | @Bean
77 | public Binding bindingDelay() {
78 | return BindingBuilder.bind(queueDelay()).to(delayExchange()).with(ROUTING_DELAY).noargs();
79 | }
80 |
81 | @Bean
82 | public Binding bindingWithInfo() {
83 | return BindingBuilder.bind(queueFirst()).to(exchange()).with(ROUTING_KEY_INFO).noargs();
84 | }
85 |
86 | @Bean
87 | public Binding bindingWithWarning() {
88 | return BindingBuilder.bind(queueSecond()).to(exchange()).with(ROUTING_KEY_WARNING).noargs();
89 | }
90 |
91 |
92 | @Bean
93 | public Binding bindingWithError() {
94 | return BindingBuilder.bind(queueThird()).to(exchange()).with(ROUTING_KEY_ERROR).noargs();
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/demo-rabbitmq/src/main/java/com/zzq/rabbitmq/ctrl/ProducerController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.rabbitmq.ctrl;
2 |
3 | import cn.hutool.core.date.LocalDateTimeUtil;
4 | import com.zzq.rabbitmq.config.AmqpConfig;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.amqp.core.AmqpTemplate;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 | @RestController
13 | @RequiredArgsConstructor
14 | @Slf4j
15 | public class ProducerController {
16 |
17 | private final AmqpTemplate amqpTemplate;
18 |
19 | /**
20 | * retry 3 times
21 | */
22 | @GetMapping("/sendToInfo/{data}")
23 | public void sendToInfo(@PathVariable String data) {
24 |
25 | amqpTemplate.convertAndSend(AmqpConfig.EXCHANGE_FIRST, AmqpConfig.ROUTING_KEY_INFO, data);
26 |
27 | }
28 |
29 | /**
30 | * manual ack
31 | */
32 |
33 | @GetMapping("/sendToWarning/{data}")
34 | public void sendToWarning(@PathVariable String data) {
35 |
36 | amqpTemplate.convertAndSend(AmqpConfig.EXCHANGE_FIRST, AmqpConfig.ROUTING_KEY_WARNING, data);
37 |
38 | }
39 |
40 | /**
41 | * Delay Message
42 | * delay 5 seconds
43 | */
44 | @GetMapping("/sendToError/{data}")
45 | public void sendToError(@PathVariable String data) {
46 |
47 | log.error("sendToError: {} , current time {}", data, LocalDateTimeUtil.now());
48 | amqpTemplate.convertAndSend(AmqpConfig.EXCHANGE_DELAY, AmqpConfig.ROUTING_DELAY, data, msg -> {
49 | msg.getMessageProperties().setExpiration("5000");
50 | return msg;
51 | }
52 | );
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/demo-rabbitmq/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 |
2 | spring:
3 | rabbitmq:
4 | addresses: [localhost:5672]
5 | username: guest
6 | password: guest
7 | listener:
8 | direct:
9 | acknowledge-mode: manual
10 |
--------------------------------------------------------------------------------
/demo-redis/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-redis
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-redis
23 |
24 |
25 |
26 | org.apache.commons
27 | commons-pool2
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-logging
33 |
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-validation
38 |
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-web
43 |
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-actuator
48 |
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-starter-test
54 |
55 |
56 |
57 |
58 | org.mariadb.jdbc
59 | mariadb-java-client
60 | runtime
61 |
62 |
63 |
64 |
65 | cn.hutool
66 | hutool-all
67 |
68 |
69 |
70 | org.projectlombok
71 | lombok
72 | true
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/demo-redis/src/main/java/com/zzq/redis/RedisAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.redis;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class RedisAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(RedisAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-redis/src/main/java/com/zzq/redis/config/CacheManagerConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.redis.config;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
5 | import com.fasterxml.jackson.annotation.PropertyAccessor;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
8 | import org.springframework.cache.CacheManager;
9 | import org.springframework.cache.annotation.EnableCaching;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 | import org.springframework.context.annotation.Primary;
13 | import org.springframework.data.redis.cache.RedisCacheConfiguration;
14 | import org.springframework.data.redis.cache.RedisCacheManager;
15 | import org.springframework.data.redis.connection.RedisConnectionFactory;
16 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
17 | import org.springframework.data.redis.serializer.RedisSerializationContext;
18 | import org.springframework.data.redis.serializer.RedisSerializer;
19 | import org.springframework.data.redis.serializer.StringRedisSerializer;
20 |
21 | import java.time.Duration;
22 |
23 | @Configuration
24 | @EnableCaching
25 | public class CacheManagerConfig {
26 | public static final String CACHE_LONG = "cache-redis-long";
27 | public static final String CACHE_SHORT = "cache-redis-short";
28 |
29 | private final RedisConnectionFactory redisConnectionFactory;
30 | private final ObjectMapper objectMapper;
31 |
32 | public CacheManagerConfig(
33 | RedisConnectionFactory redisConnectionFactory,
34 | ObjectMapper objectMapper
35 | ) {
36 | this.redisConnectionFactory = redisConnectionFactory;
37 | this.objectMapper = objectMapper.copy()
38 | .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
39 | .activateDefaultTyping(
40 | LaissezFaireSubTypeValidator.instance,
41 | ObjectMapper.DefaultTyping.NON_FINAL,
42 | JsonTypeInfo.As.WRAPPER_ARRAY);
43 | }
44 |
45 | @Bean(CACHE_LONG)
46 | public CacheManager longCacheManager() {
47 | return cacheManager("clr-", Duration.ofDays(7));
48 | }
49 |
50 | @Primary
51 | @Bean(CACHE_SHORT)
52 | public CacheManager shortCacheManager() {
53 | return cacheManager("cls-", Duration.ofMinutes(5));
54 | }
55 |
56 | private CacheManager cacheManager(String prefix, Duration duration) {
57 | RedisSerializer redisSerializer = new StringRedisSerializer();
58 | Jackson2JsonRedisSerializer> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
59 | jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
60 |
61 |
62 | RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
63 | .entryTtl(duration)
64 | .prefixCacheNameWith(prefix)
65 | .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
66 | .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
67 | .disableCachingNullValues();
68 |
69 | return RedisCacheManager.builder(redisConnectionFactory)
70 | .cacheDefaults(config)
71 | .build();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/demo-redis/src/main/java/com/zzq/redis/config/RedisTemplateConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.redis.config;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.PropertyAccessor;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.data.redis.connection.RedisConnectionFactory;
10 | import org.springframework.data.redis.core.RedisTemplate;
11 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
12 | import org.springframework.data.redis.serializer.StringRedisSerializer;
13 |
14 | @Configuration
15 | public class RedisTemplateConfig {
16 |
17 | @Bean
18 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
19 | RedisTemplate template = new RedisTemplate<>();
20 | template.setConnectionFactory(factory);
21 |
22 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
23 | ObjectMapper om = new ObjectMapper();
24 |
25 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
26 |
27 |
28 | om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
29 | jackson2JsonRedisSerializer.setObjectMapper(om);
30 |
31 |
32 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
33 |
34 | template.setKeySerializer(stringRedisSerializer);
35 | template.setHashKeySerializer(stringRedisSerializer);
36 |
37 | template.setValueSerializer(jackson2JsonRedisSerializer);
38 | template.setHashValueSerializer(jackson2JsonRedisSerializer);
39 | template.afterPropertiesSet();
40 |
41 | return template;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/demo-redis/src/main/java/com/zzq/redis/ctrl/RedisController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.redis.ctrl;
2 |
3 | import com.zzq.redis.service.RedisService;
4 | import lombok.RequiredArgsConstructor;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RequestParam;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | @RestController
10 | @RequiredArgsConstructor
11 | public class RedisController {
12 |
13 | private final RedisService redisService;
14 |
15 | /**
16 | * By redisTemplate
17 | * @param redisKey
18 | * @return
19 | */
20 | @GetMapping("/redis/template")
21 | public String redisTemplate(@RequestParam String redisKey) {
22 | return redisService.saveOneDay(redisKey);
23 | }
24 |
25 | /**
26 | * By Annotation @Cacheable
27 | */
28 | @GetMapping("/cache/annotation")
29 | public String cacheAnnotation(@RequestParam String redisKey) {
30 | return redisService.saveOneWeek(redisKey);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/demo-redis/src/main/java/com/zzq/redis/service/RedisService.java:
--------------------------------------------------------------------------------
1 | package com.zzq.redis.service;
2 |
3 | public interface RedisService {
4 | String saveOneDay(String redisKey);
5 |
6 | String saveOneWeek(String redisKey);
7 | }
8 |
--------------------------------------------------------------------------------
/demo-redis/src/main/java/com/zzq/redis/service/impl/RedisServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzq.redis.service.impl;
2 |
3 |
4 | import com.zzq.redis.config.CacheManagerConfig;
5 | import com.zzq.redis.service.RedisService;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.cache.annotation.CacheConfig;
8 | import org.springframework.cache.annotation.Cacheable;
9 | import org.springframework.data.redis.core.RedisTemplate;
10 | import org.springframework.stereotype.Service;
11 |
12 | import java.util.concurrent.TimeUnit;
13 |
14 | @RequiredArgsConstructor
15 | @CacheConfig(cacheManager = CacheManagerConfig.CACHE_LONG)
16 | @Service
17 | public class RedisServiceImpl implements RedisService {
18 |
19 | private final RedisTemplate redisTemplate;
20 | private static final String REDIS_VALUE = "hello-redis";
21 |
22 | @Override
23 | public String saveOneDay(String redisKey) {
24 | String value = redisTemplate.opsForValue().get(redisKey);
25 | if (value == null) {
26 | redisTemplate.opsForValue().set(redisKey, REDIS_VALUE, 1, TimeUnit.DAYS);
27 | value = REDIS_VALUE;
28 | }
29 | return value;
30 | }
31 |
32 |
33 | /**
34 | * update new value every day at 10AM
35 | * Same to use as @CachePut @CacheEvict
36 | * @param redisKey
37 | * @return
38 | */
39 | @Cacheable(cacheNames = "CACHE_NAME", key = "(" +
40 | "T(cn.hutool.core.date.LocalDateTimeUtil).format(" +
41 | "T(cn.hutool.core.date.LocalDateTimeUtil).now().minusHours(10),T(cn.hutool.core.date.DatePattern).NORM_DATE_PATTERN)" +
42 | "+(#redisKey))", unless = "#result == null")
43 | @Override
44 | public String saveOneWeek(String redisKey) {
45 | return REDIS_VALUE;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/demo-redis/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | management:
2 | server:
3 | port: 9001
4 | endpoints:
5 | web:
6 | base-path: /actuator
7 | exposure:
8 | include: "*"
9 | endpoint:
10 | health:
11 | show-details: always
12 |
13 | spring:
14 | redis:
15 | host: localhost
16 | port: 6379
17 | username:
18 | password:
19 | database: 0
20 | client-type: lettuce
21 | lettuce:
22 | pool:
23 | enabled: true
24 | max-idle: 4
25 | min-idle: 2
26 | max-active: 8
27 |
--------------------------------------------------------------------------------
/demo-security_jwt/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-security_jwt
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-security
26 |
27 |
28 |
29 |
30 | io.jsonwebtoken
31 | jjwt
32 | 0.9.1
33 |
34 |
35 |
36 |
37 | org.mybatis.spring.boot
38 | mybatis-spring-boot-starter
39 | 2.2.2
40 |
41 |
42 | com.baomidou
43 | mybatis-plus-boot-starter
44 | 3.5.1
45 |
46 |
47 | org.springdoc
48 | springdoc-openapi-ui
49 |
50 |
51 | org.springdoc
52 | springdoc-openapi-common
53 |
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-starter-logging
59 |
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-starter-validation
64 |
65 |
66 |
67 | org.springframework.boot
68 | spring-boot-starter-web
69 |
70 |
71 |
72 | org.springframework.boot
73 | spring-boot-starter-actuator
74 |
75 |
76 |
77 |
78 | org.springframework.boot
79 | spring-boot-starter-test
80 |
81 |
82 |
83 |
84 | org.mariadb.jdbc
85 | mariadb-java-client
86 | runtime
87 |
88 |
89 |
90 |
91 | cn.hutool
92 | hutool-all
93 |
94 |
95 |
96 | org.projectlombok
97 | lombok
98 | true
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/SecurityJWTAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SecurityJWTAppApplication {
8 | public static void main(String[] args) {
9 |
10 | SpringApplication.run(SecurityJWTAppApplication.class, args);
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/annotation/Anonymous.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | @Target({ElementType.METHOD, ElementType.TYPE})
6 | @Retention(RetentionPolicy.RUNTIME)
7 | @Documented
8 | public @interface Anonymous {
9 | }
10 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/bean/Token.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.bean;
2 |
3 | import java.util.Collection;
4 |
5 | public interface Token {
6 | Long userId();
7 | String userName();
8 | Collection authorities();
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/bean/TokenImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.bean;
2 |
3 | import lombok.Builder;
4 | import org.springframework.security.core.Authentication;
5 | import org.springframework.security.core.GrantedAuthority;
6 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
7 |
8 | import java.util.Collection;
9 | import java.util.stream.Collectors;
10 |
11 | @Builder
12 | public class TokenImpl implements Authentication ,Token{
13 |
14 | private Long userId;
15 | private String username;
16 | private Collection authorities;
17 |
18 |
19 | @Override
20 | public Collection extends GrantedAuthority> getAuthorities() {
21 | return authorities().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
22 | }
23 |
24 | @Override
25 | public Object getCredentials() {
26 | return null;
27 | }
28 |
29 | @Override
30 | public Object getDetails() {
31 | return null;
32 | }
33 |
34 | @Override
35 | public Object getPrincipal() {
36 | return null;
37 | }
38 |
39 | @Override
40 | public boolean isAuthenticated() {
41 | return true;
42 | }
43 |
44 | @Override
45 | public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
46 |
47 | }
48 |
49 | @Override
50 | public String getName() {
51 | return username;
52 | }
53 |
54 | @Override
55 | public Long userId() {
56 | return userId;
57 | }
58 |
59 | @Override
60 | public String userName() {
61 | return username;
62 | }
63 |
64 | @Override
65 | public Collection authorities() {
66 | return authorities;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/config/CS.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.config;
2 |
3 | public class CS {
4 |
5 | public static final String TOKEN_HEADER = "Authorization";
6 | public static final String TOKEN_FIELD = "_sec_t";
7 | public static final String TOKEN_SECRET = "t7w3P8X6472qWc3u";
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/config/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.config;
2 |
3 | import cn.hutool.core.lang.Pair;
4 | import cn.hutool.core.map.MapUtil;
5 | import com.zzq.security.annotation.Anonymous;
6 | import com.zzq.security.filter.TokenFilter;
7 | import lombok.RequiredArgsConstructor;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.http.HttpMethod;
11 | import org.springframework.http.HttpStatus;
12 | import org.springframework.security.authentication.AuthenticationManager;
13 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
14 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
15 | import org.springframework.security.config.annotation.web.builders.WebSecurity;
16 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
17 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
18 | import org.springframework.security.config.http.SessionCreationPolicy;
19 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
20 | import org.springframework.security.crypto.password.PasswordEncoder;
21 | import org.springframework.security.web.access.AccessDeniedHandlerImpl;
22 | import org.springframework.security.web.authentication.HttpStatusEntryPoint;
23 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
24 | import org.springframework.web.bind.annotation.RequestMethod;
25 | import org.springframework.web.method.HandlerMethod;
26 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
27 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
28 | import org.springframework.web.util.pattern.PathPattern;
29 |
30 | import java.lang.reflect.Method;
31 | import java.util.HashSet;
32 | import java.util.Map;
33 | import java.util.Objects;
34 | import java.util.Set;
35 | import java.util.stream.Collectors;
36 |
37 | @Configuration
38 | @RequiredArgsConstructor
39 | @EnableWebSecurity
40 | @EnableGlobalMethodSecurity(prePostEnabled = true)
41 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
42 |
43 | private final TokenFilter tokenFilter;
44 | private final RequestMappingHandlerMapping requestMapping;
45 |
46 | @Bean
47 | PasswordEncoder passwordEncoder() {
48 | return new BCryptPasswordEncoder();
49 | }
50 |
51 | @Bean
52 | @Override
53 | protected AuthenticationManager authenticationManager() throws Exception {
54 | return super.authenticationManager();
55 | }
56 | @Override
57 | public void configure(WebSecurity web) throws Exception {
58 | super.configure(web);
59 | }
60 |
61 |
62 | @Override
63 | protected void configure(HttpSecurity http) throws Exception {
64 |
65 | Map> anonymousUrls = getAnonymousUrls();
66 |
67 | http
68 | .csrf().disable()
69 | .cors().disable()
70 | .exceptionHandling()
71 | .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
72 | .accessDeniedHandler(new AccessDeniedHandlerImpl())
73 | .and()
74 | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
75 | .authorizeRequests()
76 | .antMatchers("/swagger/**").permitAll()
77 | .antMatchers("/actuator/**").permitAll()
78 | .antMatchers("/login/**").permitAll()
79 | .antMatchers(HttpMethod.OPTIONS).denyAll()
80 | .antMatchers(HttpMethod.TRACE).denyAll()
81 | .antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethod.GET).toArray(new String[0])).permitAll()
82 | .antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethod.POST).toArray(new String[0])).permitAll()
83 | .antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethod.DELETE).toArray(new String[0])).permitAll()
84 | .antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethod.PUT).toArray(new String[0])).permitAll()
85 | .antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethod.PATCH).toArray(new String[0])).permitAll()
86 | .antMatchers(anonymousUrls.get(RequestMethod.OPTIONS).toArray(new String[0])).permitAll()
87 | .anyRequest().authenticated()
88 | ;
89 |
90 | http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
91 |
92 | }
93 |
94 |
95 | private Map> getAnonymousUrls() {
96 | // init
97 | Map> urls = MapUtil.of(
98 | Pair.of(RequestMethod.GET, new HashSet<>()),
99 | Pair.of(RequestMethod.POST, new HashSet<>()),
100 | Pair.of(RequestMethod.DELETE, new HashSet<>()),
101 | Pair.of(RequestMethod.PUT, new HashSet<>()),
102 | Pair.of(RequestMethod.PATCH, new HashSet<>()),
103 | Pair.of(RequestMethod.OPTIONS, new HashSet<>())
104 | );
105 |
106 | // get ctrl method
107 | Map handlerMethods = requestMapping.getHandlerMethods();
108 | for (Map.Entry entry : handlerMethods.entrySet()) {
109 | RequestMappingInfo mappingInfo = entry.getKey();
110 |
111 | // check has annotation
112 | boolean hasAnonymousAnnotation = Objects.nonNull(entry.getValue().getMethodAnnotation(Anonymous.class));
113 |
114 | if (!hasAnonymousAnnotation) {
115 | Method targetMethod = Objects.requireNonNull(entry.getValue().getMethod());
116 | Class> targetClass = Objects.requireNonNull(targetMethod.getDeclaringClass());
117 |
118 | hasAnonymousAnnotation = Objects.nonNull(targetClass.getAnnotation(Anonymous.class));
119 | }
120 |
121 | if (!hasAnonymousAnnotation) {
122 | continue;
123 | }
124 |
125 | // get method
126 | Set methods = mappingInfo.getMethodsCondition().getMethods()
127 | .stream()
128 | .filter(requestMethod -> requestMethod != RequestMethod.OPTIONS)
129 | .collect(Collectors.toSet());
130 |
131 | if (methods.size() == 0) {
132 | methods = Set.of(RequestMethod.OPTIONS);
133 | }
134 |
135 | // get url
136 | Set patterns = Objects.nonNull(mappingInfo.getPathPatternsCondition()) ?
137 | mappingInfo.getPathPatternsCondition().getPatterns()
138 | .stream()
139 | .map(PathPattern::getPatternString)
140 | .collect(Collectors.toSet()) : Set.of();
141 |
142 | for (RequestMethod method : methods) {
143 | Set target = urls.get(method);
144 | if (Objects.nonNull(target))
145 | target.addAll(patterns);
146 | }
147 | }
148 |
149 | return urls;
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/ctrl/LoginController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.ctrl;
2 |
3 | import com.zzq.security.bean.TokenImpl;
4 | import com.zzq.security.dto.LoginRequest;
5 | import com.zzq.security.service.LoginService;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.security.access.prepost.PreAuthorize;
8 | import org.springframework.security.core.GrantedAuthority;
9 | import org.springframework.security.core.context.SecurityContextHolder;
10 | import org.springframework.validation.annotation.Validated;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.PostMapping;
13 | import org.springframework.web.bind.annotation.RequestBody;
14 | import org.springframework.web.bind.annotation.RestController;
15 |
16 | @RestController
17 | @RequiredArgsConstructor
18 | public class LoginController {
19 |
20 | private final LoginService loginService;
21 |
22 | @PostMapping("/login")
23 | public String login(@RequestBody @Validated LoginRequest loginRequest) {
24 |
25 |
26 | return loginService.login(loginRequest.getUsername(), loginRequest.getPassword());
27 |
28 | }
29 |
30 | @PreAuthorize("hasRole('ROLE_ADMIN') && hasAuthority('LOL')")
31 | @GetMapping("/test")
32 | public String test(){
33 | TokenImpl authentication = (TokenImpl) SecurityContextHolder.getContext().getAuthentication();
34 | Long userId = authentication.userId();
35 | String userName = authentication.userName();
36 | for (GrantedAuthority authority : authentication.getAuthorities()) {
37 | System.out.println(authority);
38 | }
39 | System.out.println(userName);
40 | System.out.println(userId);
41 |
42 | return userName;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/dto/LoginRequest.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.dto;
2 |
3 | import lombok.Data;
4 |
5 | import javax.validation.constraints.NotBlank;
6 |
7 | @Data
8 | public class LoginRequest {
9 |
10 | @NotBlank
11 | private String username;
12 |
13 | @NotBlank
14 | private String password;
15 | }
16 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/entity/Permission.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 | import lombok.experimental.Accessors;
10 |
11 |
12 | @Getter
13 | @Setter
14 | @Accessors(chain = true)
15 | @TableName("permission")
16 | public class Permission {
17 |
18 | @TableId(value = "permission_id", type = IdType.AUTO)
19 | private Long permissionId;
20 |
21 | @TableField("permission_name")
22 | private String permissionName;
23 | }
24 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/entity/Role.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 | import lombok.experimental.Accessors;
10 |
11 | @Getter
12 | @Setter
13 | @Accessors(chain = true)
14 | @TableName("role")
15 | public class Role {
16 |
17 | @TableId(value = "role_id", type = IdType.AUTO)
18 | private Long roleId;
19 |
20 | @TableField("role_name")
21 | private String roleName;
22 | }
23 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/entity/RolePermission.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 | import lombok.experimental.Accessors;
10 |
11 | @Getter
12 | @Setter
13 | @Accessors(chain = true)
14 | @TableName("role_permission")
15 | public class RolePermission {
16 |
17 | @TableId(value = "role_permission_id", type = IdType.AUTO)
18 | private Long rolePermissionId;
19 |
20 | @TableField("role_id")
21 | private Long roleId;
22 |
23 | @TableField("permission_id")
24 | private Long permissionId;
25 | }
26 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/entity/User.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 | import lombok.experimental.Accessors;
10 |
11 | @Getter
12 | @Setter
13 | @Accessors(chain = true)
14 | @TableName("user")
15 | public class User {
16 |
17 | @TableId(value = "user_id", type = IdType.AUTO)
18 | private Long userId;
19 |
20 | @TableField("username")
21 | private String username;
22 |
23 | @TableField("password")
24 | private String password;
25 | }
26 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/entity/UserRole.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 | import lombok.experimental.Accessors;
10 |
11 | @Getter
12 | @Setter
13 | @Accessors(chain = true)
14 | @TableName("user_role")
15 | public class UserRole {
16 |
17 | @TableId(value = "user_role_id", type = IdType.AUTO)
18 | private Long userRoleId;
19 |
20 | @TableField("user_id")
21 | private Long userId;
22 |
23 | @TableField("role_id")
24 | private Long roleId;
25 | }
26 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/filter/TokenFilter.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.filter;
2 |
3 |
4 | import cn.hutool.core.util.StrUtil;
5 | import com.zzq.security.bean.TokenImpl;
6 | import com.zzq.security.config.CS;
7 | import com.zzq.security.service.TokenService;
8 | import lombok.RequiredArgsConstructor;
9 | import org.springframework.security.core.context.SecurityContextHolder;
10 | import org.springframework.stereotype.Component;
11 |
12 | import javax.servlet.*;
13 | import javax.servlet.http.HttpServletRequest;
14 | import java.io.IOException;
15 |
16 | import static java.util.Objects.isNull;
17 |
18 | @RequiredArgsConstructor
19 | @Component
20 | public class TokenFilter implements Filter {
21 |
22 | private final TokenService tokenService;
23 |
24 | @Override
25 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
26 | if (!(servletRequest instanceof HttpServletRequest)){
27 | filterChain.doFilter(servletRequest,servletResponse);
28 | return;
29 | }
30 |
31 | String token = ((HttpServletRequest) servletRequest).getHeader(CS.TOKEN_HEADER);
32 | if (isNull(token)){
33 | token = servletRequest.getParameter(CS.TOKEN_FIELD);
34 | }
35 | // has token
36 | if (StrUtil.isNotBlank(token)){
37 | TokenImpl parseToken = tokenService.parseToken(token);
38 |
39 | SecurityContextHolder.getContext().setAuthentication(parseToken);
40 | }
41 |
42 | filterChain.doFilter(servletRequest,servletResponse);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/PermissionMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzq.security.entity.Permission;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface PermissionMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/RoleMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzq.security.entity.Role;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface RoleMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/RolePermissionMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzq.security.entity.RolePermission;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface RolePermissionMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/UserMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzq.security.entity.User;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface UserMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/UserRoleMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzq.security.entity.UserRole;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface UserRoleMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/xml/PermissionMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | permission_id, permission_name
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/xml/RoleMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | role_id, role_name
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/xml/RolePermissionMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | role_permission_id
13 | ,role_id, permission_id
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/xml/UserMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | user_id,username, password
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/mapper/xml/UserRoleMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | user_role_id,user_id, role_id
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/service/LoginService.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.service;
2 |
3 | public interface LoginService {
4 |
5 |
6 | String login(String username, String password);
7 | }
8 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/service/TokenService.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.service;
2 |
3 | import com.zzq.security.bean.TokenImpl;
4 |
5 | import java.util.Map;
6 |
7 | public interface TokenService {
8 |
9 | TokenImpl parseToken(String token);
10 |
11 |
12 | String generateToken(Map map);
13 | }
14 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/service/impl/LoginServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.service.impl;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.zzq.security.entity.*;
5 | import com.zzq.security.mapper.*;
6 | import com.zzq.security.service.LoginService;
7 | import com.zzq.security.service.TokenService;
8 | import lombok.RequiredArgsConstructor;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.security.crypto.password.PasswordEncoder;
11 | import org.springframework.stereotype.Service;
12 |
13 | import java.util.HashMap;
14 | import java.util.List;
15 | import java.util.Set;
16 | import java.util.stream.Collectors;
17 |
18 | @Service
19 | @RequiredArgsConstructor
20 | @Slf4j
21 | public class LoginServiceImpl implements LoginService {
22 |
23 | private final UserMapper userMapper;
24 | private final PasswordEncoder passwordEncoder;
25 | private final TokenService tokenService;
26 | private final UserRoleMapper userRoleMapper;
27 | private final RolePermissionMapper rolePermissionMapper;
28 | private final PermissionMapper permissionMapper;
29 | private final RoleMapper roleMapper;
30 |
31 | @Override
32 | public String login(String username, String password) {
33 | String result;
34 | log.info(password + "--------encode-------" + passwordEncoder.encode(password));
35 | User user = userMapper.selectOne(new LambdaQueryWrapper()
36 | .eq(User::getUsername, username)
37 | );
38 | boolean matches = passwordEncoder.matches(password, user.getPassword());
39 | if (matches) {
40 | // login successful return token
41 | HashMap map = new HashMap<>();
42 | map.put("userId", user.getUserId());
43 | map.put("username", user.getUsername());
44 |
45 | //current user -> roleIds
46 | List roleIds = userRoleMapper.selectList(new LambdaQueryWrapper()
47 | .eq(UserRole::getUserId, user.getUserId())
48 | .select(UserRole::getRoleId)).stream().map(UserRole::getRoleId).collect(Collectors.toList());
49 | //current user -> roleNames
50 | Set roleNames = roleMapper.selectList(new LambdaQueryWrapper()
51 | .in(Role::getRoleId, roleIds)
52 | ).stream().map(Role::getRoleName).collect(Collectors.toSet());
53 |
54 | //current user -> permissionIds
55 | Set permissionIds = rolePermissionMapper.selectList(new LambdaQueryWrapper()
56 | .in(RolePermission::getRoleId, roleIds)
57 | ).stream().map(RolePermission::getPermissionId).collect(Collectors.toSet());
58 |
59 | //current user -> permissionNames
60 | Set permissionNames = permissionMapper.selectList(new LambdaQueryWrapper()
61 | .in(Permission::getPermissionId, permissionIds)
62 | ).stream().map(Permission::getPermissionName).collect(Collectors.toSet());
63 |
64 | roleNames.addAll(permissionNames);
65 | map.put("authorities", roleNames);
66 | result = tokenService.generateToken(map);
67 | } else {
68 | result = "username or password error";
69 | }
70 |
71 | return result;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/service/impl/TokenServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.service.impl;
2 |
3 | import com.zzq.security.bean.TokenImpl;
4 | import com.zzq.security.config.CS;
5 | import com.zzq.security.service.TokenService;
6 | import io.jsonwebtoken.*;
7 | import org.springframework.stereotype.Service;
8 |
9 | import java.util.Collection;
10 | import java.util.Date;
11 | import java.util.Map;
12 |
13 | @Service
14 | public class TokenServiceImpl implements TokenService {
15 |
16 | @SuppressWarnings("unchecked")
17 | @Override
18 | public TokenImpl parseToken(String token) {
19 | Jws claimsJws = Jwts.parser().setSigningKey(CS.TOKEN_SECRET)
20 | .parseClaimsJws(token);
21 | Claims body = claimsJws.getBody();
22 |
23 | return TokenImpl.builder().authorities((Collection) body.get("authorities"))
24 | .userId(((Integer) body.get("userId")).longValue())
25 | .username((String) body.get("username"))
26 | .build();
27 |
28 |
29 | }
30 |
31 |
32 | @Override
33 | public String generateToken(Map map) {
34 | return Jwts.builder().signWith(SignatureAlgorithm.HS256, CS.TOKEN_SECRET)
35 | // 1 year
36 | .setExpiration(new Date(System.currentTimeMillis() + (60L * 60 * 24 * 365 * 1000)))
37 | .setClaims(map)
38 | .compact();
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/java/com/zzq/security/utils/SecContextUtil.java:
--------------------------------------------------------------------------------
1 | package com.zzq.security.utils;
2 |
3 | import com.zzq.security.bean.TokenImpl;
4 | import org.springframework.security.core.context.SecurityContextHolder;
5 |
6 | import java.util.Collection;
7 |
8 | public class SecContextUtil {
9 |
10 | public Long getUserId() {
11 | return authentication().userId();
12 | }
13 |
14 | public String getUsername() {
15 | return authentication().userName();
16 | }
17 |
18 | public Collection authorities() {
19 | return authentication().authorities();
20 | }
21 |
22 | public TokenImpl authentication() {
23 | return (TokenImpl) SecurityContextHolder.getContext().getAuthentication();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | spring:
2 | datasource:
3 | url: jdbc:mariadb://localhost:3306/demo_security
4 | username: root
5 | password: root
6 | hikari:
7 | pool-name: HikariCP
8 | connection-timeout: 3000
9 | connection-test-query: SELECT 1
10 | maximum-pool-size: 64
11 | minimum-idle: 4
12 | idle-timeout: 180000
13 | max-lifetime: 1800000
14 |
15 | logging:
16 | level:
17 | com:
18 | test:
19 | dao: debug
20 |
21 | springdoc:
22 | swagger-ui:
23 | path: /swagger/index.html
24 | api-docs:
25 | path: /swagger/v3/api-docs
26 |
27 |
--------------------------------------------------------------------------------
/demo-security_jwt/src/main/resources/sql/security_jwt.sql:
--------------------------------------------------------------------------------
1 | /*
2 | SQLyog Ultimate v11.25 (64 bit)
3 | MySQL - 10.6.7-MariaDB : Database - demo_security
4 | *********************************************************************
5 | */
6 |
7 | /*!40101 SET NAMES utf8 */;
8 |
9 | /*!40101 SET SQL_MODE=''*/;
10 |
11 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
12 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
13 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
14 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
15 | CREATE DATABASE /*!32312 IF NOT EXISTS*/`demo_security` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
16 |
17 | USE `demo_security`;
18 |
19 | /*Table structure for table `permission` */
20 |
21 | DROP TABLE IF EXISTS `permission`;
22 |
23 | CREATE TABLE `permission` (
24 | `permission_id` bigint(20) NOT NULL AUTO_INCREMENT,
25 | `permission_name` varchar(32) NOT NULL,
26 | PRIMARY KEY (`permission_id`)
27 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
28 |
29 | /*Data for the table `permission` */
30 |
31 | insert into `permission`(`permission_id`,`permission_name`) values (1,'QUERY'),(2,'CREATE'),(3,'UPDATE'),(4,'DELETE');
32 |
33 | /*Table structure for table `role` */
34 |
35 | DROP TABLE IF EXISTS `role`;
36 |
37 | CREATE TABLE `role` (
38 | `role_id` bigint(20) NOT NULL AUTO_INCREMENT,
39 | `role_name` varchar(32) NOT NULL,
40 | PRIMARY KEY (`role_id`)
41 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
42 |
43 | /*Data for the table `role` */
44 |
45 | insert into `role`(`role_id`,`role_name`) values (1,'ROLE_ADMIN'),(2,'ROLE_MANAGER'),(3,'ROLE_NP');
46 |
47 | /*Table structure for table `role_permission` */
48 |
49 | DROP TABLE IF EXISTS `role_permission`;
50 |
51 | CREATE TABLE `role_permission` (
52 | `role_permission_id` bigint(20) NOT NULL AUTO_INCREMENT,
53 | `role_id` bigint(20) NOT NULL,
54 | `permission_id` bigint(20) NOT NULL,
55 | PRIMARY KEY (`role_permission_id`)
56 | ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4;
57 |
58 | /*Data for the table `role_permission` */
59 |
60 | insert into `role_permission`(`role_permission_id`,`role_id`,`permission_id`) values (1,1,1),(2,1,2),(3,1,3),(4,1,4),(5,2,1),(6,2,2),(7,2,3),(8,3,1),(9,3,2);
61 |
62 | /*Table structure for table `user` */
63 |
64 | DROP TABLE IF EXISTS `user`;
65 |
66 | CREATE TABLE `user` (
67 | `user_id` bigint(20) NOT NULL AUTO_INCREMENT,
68 | `username` varchar(32) NOT NULL,
69 | `password` varchar(64) NOT NULL,
70 | PRIMARY KEY (`user_id`)
71 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
72 |
73 | /*Data for the table `user` */
74 |
75 | insert into `user`(`user_id`,`username`,`password`) values (1,'zzq','$2a$10$UyCgLflFZrTD4vBzx23N4.xe/u5IG1spmGdih/LDbMVBVZGBnZwda');
76 |
77 | /*Table structure for table `user_role` */
78 |
79 | DROP TABLE IF EXISTS `user_role`;
80 |
81 | CREATE TABLE `user_role` (
82 | `user_role_id` bigint(20) NOT NULL AUTO_INCREMENT,
83 | `user_id` bigint(20) NOT NULL,
84 | `role_id` bigint(20) NOT NULL,
85 | PRIMARY KEY (`user_role_id`)
86 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
87 |
88 | /*Data for the table `user_role` */
89 |
90 | insert into `user_role`(`user_role_id`,`user_id`,`role_id`) values (1,1,1);
91 |
92 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
93 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
94 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
95 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
96 | /*
97 | SQLyog Ultimate v11.25 (64 bit)
98 | MySQL - 10.6.7-MariaDB : Database - demo_security
99 | *********************************************************************
100 | */
101 |
102 | /*!40101 SET NAMES utf8 */;
103 |
104 | /*!40101 SET SQL_MODE=''*/;
105 |
106 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
107 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
108 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
109 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
110 | CREATE DATABASE /*!32312 IF NOT EXISTS*/`demo_security` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
111 |
112 | USE `demo_security`;
113 |
114 | /*Table structure for table `permission` */
115 |
116 | DROP TABLE IF EXISTS `permission`;
117 |
118 | CREATE TABLE `permission` (
119 | `permission_id` bigint(20) NOT NULL AUTO_INCREMENT,
120 | `permission_name` varchar(32) NOT NULL,
121 | PRIMARY KEY (`permission_id`)
122 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
123 |
124 | /*Data for the table `permission` */
125 |
126 | insert into `permission`(`permission_id`,`permission_name`) values (1,'QUERY'),(2,'CREATE'),(3,'UPDATE'),(4,'DELETE');
127 |
128 | /*Table structure for table `role` */
129 |
130 | DROP TABLE IF EXISTS `role`;
131 |
132 | CREATE TABLE `role` (
133 | `role_id` bigint(20) NOT NULL AUTO_INCREMENT,
134 | `role_name` varchar(32) NOT NULL,
135 | PRIMARY KEY (`role_id`)
136 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
137 |
138 | /*Data for the table `role` */
139 |
140 | insert into `role`(`role_id`,`role_name`) values (1,'ROLE_ADMIN'),(2,'ROLE_MANAGER'),(3,'ROLE_NP');
141 |
142 | /*Table structure for table `role_permission` */
143 |
144 | DROP TABLE IF EXISTS `role_permission`;
145 |
146 | CREATE TABLE `role_permission` (
147 | `role_permission_id` bigint(20) NOT NULL AUTO_INCREMENT,
148 | `role_id` bigint(20) NOT NULL,
149 | `permission_id` bigint(20) NOT NULL,
150 | PRIMARY KEY (`role_permission_id`)
151 | ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4;
152 |
153 | /*Data for the table `role_permission` */
154 |
155 | insert into `role_permission`(`role_permission_id`,`role_id`,`permission_id`) values (1,1,1),(2,1,2),(3,1,3),(4,1,4),(5,2,1),(6,2,2),(7,2,3),(8,3,1),(9,3,2);
156 |
157 | /*Table structure for table `user` */
158 |
159 | DROP TABLE IF EXISTS `user`;
160 |
161 | CREATE TABLE `user` (
162 | `user_id` bigint(20) NOT NULL AUTO_INCREMENT,
163 | `username` varchar(32) NOT NULL,
164 | `password` varchar(64) NOT NULL,
165 | PRIMARY KEY (`user_id`)
166 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
167 |
168 | /*Data for the table `user` */
169 |
170 | insert into `user`(`user_id`,`username`,`password`) values (1,'zzq','$2a$10$UyCgLflFZrTD4vBzx23N4.xe/u5IG1spmGdih/LDbMVBVZGBnZwda');
171 |
172 | /*Table structure for table `user_role` */
173 |
174 | DROP TABLE IF EXISTS `user_role`;
175 |
176 | CREATE TABLE `user_role` (
177 | `user_role_id` bigint(20) NOT NULL AUTO_INCREMENT,
178 | `user_id` bigint(20) NOT NULL,
179 | `role_id` bigint(20) NOT NULL,
180 | PRIMARY KEY (`user_role_id`)
181 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
182 |
183 | /*Data for the table `user_role` */
184 |
185 | insert into `user_role`(`user_role_id`,`user_id`,`role_id`) values (1,1,1);
186 |
187 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
188 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
189 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
190 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
191 |
--------------------------------------------------------------------------------
/demo-swagger/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-swagger
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 | org.springdoc
23 | springdoc-openapi-ui
24 |
25 |
26 | org.springdoc
27 | springdoc-openapi-common
28 |
29 |
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-logging
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-validation
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-web
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-actuator
49 |
50 |
51 |
52 |
53 | org.springframework.boot
54 | spring-boot-starter-test
55 |
56 |
57 |
58 |
59 | org.mariadb.jdbc
60 | mariadb-java-client
61 | runtime
62 |
63 |
64 |
65 |
66 | cn.hutool
67 | hutool-all
68 |
69 |
70 |
71 | org.projectlombok
72 | lombok
73 | true
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/demo-swagger/src/main/java/com/zzq/swagger/SwaggerAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.swagger;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 |
7 | @SpringBootApplication
8 | public class SwaggerAppApplication {
9 | public static void main(String[] args) {
10 | SpringApplication.run(SwaggerAppApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/demo-swagger/src/main/java/com/zzq/swagger/config/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.swagger.config;
2 |
3 |
4 | import io.swagger.v3.oas.models.security.SecurityRequirement;
5 | import io.swagger.v3.oas.models.security.SecurityScheme;
6 | import org.springdoc.core.customizers.OpenApiCustomiser;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 |
11 | @Configuration
12 | public class SwaggerConfig {
13 |
14 |
15 | @Bean
16 | OpenApiCustomiser openApiCustomiser() {
17 | final String securitySchemeName = "Token";
18 |
19 | return openApi -> {
20 | openApi.addSecurityItem(new SecurityRequirement().addList(securitySchemeName));
21 | openApi.getComponents().addSecuritySchemes(
22 | securitySchemeName,
23 | new SecurityScheme()
24 | .name(securitySchemeName)
25 | .type(SecurityScheme.Type.HTTP)
26 | .scheme("bearer")
27 | .bearerFormat("JWT")
28 | );
29 | };
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/demo-swagger/src/main/java/com/zzq/swagger/ctrl/SwaggerController.java:
--------------------------------------------------------------------------------
1 | package com.zzq.swagger.ctrl;
2 |
3 | import io.swagger.v3.oas.annotations.Operation;
4 | import io.swagger.v3.oas.annotations.tags.Tag;
5 | import org.springframework.web.bind.annotation.*;
6 |
7 | /**
8 | * http://localhost:8080/swagger/swagger-ui/index.html
9 | */
10 | @RestController
11 | @Tag(name = "SwaggerController")
12 | public class SwaggerController {
13 |
14 |
15 | @GetMapping
16 | @Operation(operationId = "get", description = "GET DATA")
17 | public String get() {
18 | return "Hello GET";
19 | }
20 |
21 | @DeleteMapping
22 | @Operation(operationId = "delete", description = "DELETE DATA")
23 | public String delete() {
24 | return "Hello Delete";
25 | }
26 |
27 | @PostMapping
28 | @Operation(operationId = "post", description = "POST DATA")
29 | public String post() {
30 | return "Hello POST";
31 | }
32 |
33 | @PutMapping
34 | @Operation(operationId = "put", description = "PUT DATA")
35 | public String put() {
36 | return "Hello PUT";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/demo-swagger/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 |
2 | springdoc:
3 | swagger-ui:
4 | path: /swagger/index.html
5 | api-docs:
6 | path: /swagger/v3/api-docs
7 |
--------------------------------------------------------------------------------
/demo-websocket/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot-summary
7 | com.zzq
8 | Final
9 |
10 | 4.0.0
11 |
12 | demo-websocket
13 |
14 |
15 | 11
16 | 11
17 |
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-websocket
24 |
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-logging
30 |
31 |
32 |
33 | com.alibaba
34 | fastjson
35 | 1.2.79
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-validation
40 |
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-web
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-actuator
50 |
51 |
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-starter-test
56 |
57 |
58 |
59 |
60 | org.mariadb.jdbc
61 | mariadb-java-client
62 | runtime
63 |
64 |
65 |
66 |
67 | cn.hutool
68 | hutool-all
69 |
70 |
71 |
72 | org.projectlombok
73 | lombok
74 | true
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/demo-websocket/src/main/java/com/zzq/websocket/WebSocketAppApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzq.websocket;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class WebSocketAppApplication {
8 | public static void main(String[] args) {
9 | SpringApplication.run(WebSocketAppApplication.class, args);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/demo-websocket/src/main/java/com/zzq/websocket/config/WebSocketConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzq.websocket.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.socket.server.standard.ServerEndpointExporter;
6 |
7 | @Configuration
8 | public class WebSocketConfig {
9 |
10 | @Bean
11 | public ServerEndpointExporter serverEndpointExporter() {
12 |
13 | return new ServerEndpointExporter();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo-websocket/src/main/java/com/zzq/websocket/server/WebSocketServer.java:
--------------------------------------------------------------------------------
1 | package com.zzq.websocket.server;
2 |
3 |
4 | import com.alibaba.fastjson.JSON;
5 | import com.alibaba.fastjson.JSONObject;
6 | import io.micrometer.core.instrument.util.StringUtils;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | import org.springframework.stereotype.Component;
10 |
11 | import javax.websocket.*;
12 | import javax.websocket.server.PathParam;
13 | import javax.websocket.server.ServerEndpoint;
14 | import java.io.IOException;
15 | import java.util.concurrent.ConcurrentHashMap;
16 |
17 | @Component
18 | @Slf4j
19 | @ServerEndpoint("/api/pushMessage/{userId}")
20 | public class WebSocketServer {
21 |
22 | private static int onlineCount = 0;
23 | private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>();
24 | private Session session;
25 | private String userId = "";
26 |
27 | /**
28 | * The method called when the connection is established successfully
29 | */
30 | @OnOpen
31 | public void onOpen(Session session, @PathParam("userId") String userId) {
32 | this.session = session;
33 | this.userId = userId;
34 | if (webSocketMap.containsKey(userId)) {
35 | webSocketMap.remove(userId);
36 |
37 | webSocketMap.put(userId, this);
38 | } else {
39 |
40 | webSocketMap.put(userId, this);
41 |
42 | addOnlineCount();
43 | }
44 | log.info("user connected: " + userId + ", current online count:" + getOnlineCount());
45 | sendMessage("connection successful");
46 | }
47 |
48 | /**
49 | * connection closed method to call
50 | */
51 | @OnClose
52 | public void onClose() {
53 | if (webSocketMap.containsKey(userId)) {
54 | webSocketMap.remove(userId);
55 | subOnlineCount();
56 | }
57 | log.info("user leaving: Id" + userId + " ,current online count:" + getOnlineCount());
58 | }
59 |
60 | /**
61 | * Method to be called when a client message is received
62 | **/
63 | @OnMessage
64 | public void onMessage(String message, Session session) {
65 | log.info("current user :" + userId + ", message:" + message);
66 |
67 | if (StringUtils.isNotBlank(message)) {
68 | try {
69 | JSONObject jsonObject = JSON.parseObject(message);
70 | jsonObject.put("fromUserId", this.userId);
71 | String toUserId = jsonObject.getString("toUserId");
72 |
73 | if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
74 | webSocketMap.get(toUserId).sendMessage(message);
75 | } else {
76 | log.error("toUserId: " + toUserId + " is not online");
77 | }
78 | } catch (Exception e) {
79 | e.printStackTrace();
80 | }
81 | }
82 | }
83 |
84 |
85 | @OnError
86 | public void onError(Session session, Throwable error) {
87 | log.error("error userId: " + this.userId + ", reason: " + error.getMessage());
88 | error.printStackTrace();
89 | }
90 |
91 |
92 | public void sendMessage(String message) {
93 | try {
94 | this.session.getBasicRemote().sendText(message);
95 | } catch (IOException e) {
96 | e.printStackTrace();
97 | }
98 | }
99 |
100 |
101 | public static synchronized int getOnlineCount() {
102 | return onlineCount;
103 | }
104 |
105 |
106 | public static synchronized void addOnlineCount() {
107 | WebSocketServer.onlineCount++;
108 | }
109 |
110 |
111 | public static synchronized void subOnlineCount() {
112 | WebSocketServer.onlineCount--;
113 | }
114 |
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/demo-websocket/src/main/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
38 |
39 |
40 |
41 | Socket Opener Id:
42 | toUserId and content:
43 |
44 | click:
45 | click:
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.zzq
8 | springboot-summary
9 | Final
10 |
11 | demo-flyway
12 | demo-redis
13 | demo-quartz
14 | demo-rabbitmq
15 | demo-security_jwt
16 | demo-poi
17 | demo-swagger
18 | demo-limiter
19 | demo-email
20 | demo-http
21 | demo-multithreading
22 | demo-justauth
23 | demo-google_authenticator
24 | demo-i18n
25 | demo-websocket
26 |
27 | backend
28 | pom
29 |
30 |
31 | 11
32 | 11
33 | 2.2.2
34 | 3.5.1
35 | 5.7.20
36 | 3.9
37 | 3.0.0
38 | 1.6.6
39 | 1.4.5
40 | 6.1.5
41 |
42 |
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-parent
47 | 2.6.3
48 |
49 |
50 |
51 |
52 | org.mybatis.spring.boot
53 | mybatis-spring-boot-starter
54 | ${mybatis-starter.version}
55 |
56 |
57 | com.baomidou
58 | mybatis-plus-boot-starter
59 | ${mybatis-plus.version}
60 |
61 |
62 |
63 | cn.hutool
64 | hutool-all
65 | ${hutool.version}
66 |
67 |
68 | org.apache.poi
69 | poi-ooxml
70 | ${poi.version}
71 |
72 |
73 |
74 | org.apache.poi
75 | poi
76 | ${poi.version}
77 |
78 |
79 |
80 |
81 | org.springdoc
82 | springdoc-openapi-ui
83 | ${spring-doc.version}
84 |
85 |
86 | org.springdoc
87 | springdoc-openapi-common
88 | ${spring-doc.version}
89 |
90 |
91 |
92 | javax.mail
93 | mail
94 | ${javax-mail.version}
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------