├── .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 |
14 |
Info
15 |
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 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 | --------------------------------------------------------------------------------