├── 006-helloworld-configurationproperties ├── src │ └── main │ │ ├── resources │ │ ├── application.properties │ │ └── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ └── java │ │ └── com │ │ └── stonie │ │ └── springnotes │ │ ├── config │ │ └── StonieConfig.java │ │ ├── ConfigurationPropertiesApp.java │ │ ├── ConfigurationPropertiesController.java │ │ └── properties │ │ └── StonieProperties.java ├── README.md └── pom.xml ├── README.md ├── .gitignore ├── 001-helloworld ├── src │ └── main │ │ └── java │ │ └── com │ │ └── stonie │ │ └── springnotes │ │ ├── HelloWorldApp.java │ │ └── HelloWorldController.java ├── pom.xml └── README.md ├── 004-helloworld-springbootapplication ├── src │ └── main │ │ └── java │ │ └── com │ │ └── stonie │ │ └── springnotes │ │ ├── SpringBootController.java │ │ └── SpringBootApp.java ├── pom.xml └── README.md ├── 005-helloworld-configuration ├── src │ └── main │ │ └── java │ │ └── com │ │ └── stonie │ │ └── springnotes │ │ ├── ConfigurationApp.java │ │ ├── config │ │ └── TestConfig.java │ │ ├── service │ │ └── TestService.java │ │ └── ConfigurationController.java ├── pom.xml └── README.md ├── 002-helloworld-requestmapping ├── src │ └── main │ │ └── java │ │ └── com │ │ └── stonie │ │ └── springnotes │ │ ├── RequestMappingApp.java │ │ └── RequestMappingController.java ├── pom.xml └── README.md ├── 003-helloworld-restcontroller ├── src │ └── main │ │ └── java │ │ └── com │ │ └── stonie │ │ └── springnotes │ │ ├── RestControllerApp.java │ │ ├── RestfulController.java │ │ └── NormalController.java ├── README.md └── pom.xml └── pom.xml /006-helloworld-configurationproperties/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | com.stonie.hello-title=Hello 2 | com.stonie.hello-name=Zhangsan 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-notes 2 | 3 | Learn Spring & Spring Boot & Spring Cloud & other Spring related projects step by step. 4 | 5 | ## 组件列表 6 | 7 | |组件|版本| 8 | |----|----| 9 | |spring|5.2.7.RELEASE| 10 | |spring boot|2.3.1.RELEASE| 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # idea 2 | *.iml 3 | .idea 4 | 5 | # Compiled class file 6 | *.class 7 | 8 | # Log file 9 | *.log 10 | 11 | # BlueJ files 12 | *.ctxt 13 | 14 | # Mobile Tools for Java (J2ME) 15 | .mtj.tmp/ 16 | 17 | # Package Files # 18 | target 19 | *.jar 20 | *.war 21 | *.nar 22 | *.ear 23 | *.zip 24 | *.tar.gz 25 | *.rar 26 | 27 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 28 | hs_err_pid* 29 | -------------------------------------------------------------------------------- /001-helloworld/src/main/java/com/stonie/springnotes/HelloWorldApp.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class HelloWorldApp { 8 | 9 | public static void main( String[] args ) { 10 | SpringApplication.run(HelloWorldApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /001-helloworld/src/main/java/com/stonie/springnotes/HelloWorldController.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class HelloWorldController { 8 | 9 | @RequestMapping("/") 10 | public String index() { 11 | return "Hello World!"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /006-helloworld-configurationproperties/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "com.stonie.hello-name", 5 | "type": "java.lang.String", 6 | "description": "The name to say hello." 7 | }, { 8 | "name": "com.stonie.hello-title", 9 | "type": "java.lang.String", 10 | "description": "Hello or Hi or other hello words." 11 | } 12 | ] } -------------------------------------------------------------------------------- /004-helloworld-springbootapplication/src/main/java/com/stonie/springnotes/SpringBootController.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class SpringBootController { 8 | 9 | @RequestMapping("/") 10 | public String index() { 11 | return "Hello World!"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /005-helloworld-configuration/src/main/java/com/stonie/springnotes/ConfigurationApp.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ConfigurationApp { 8 | 9 | public static void main( String[] args ) { 10 | SpringApplication.run(ConfigurationApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /002-helloworld-requestmapping/src/main/java/com/stonie/springnotes/RequestMappingApp.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RequestMappingApp { 8 | 9 | public static void main( String[] args ) { 10 | SpringApplication.run(RequestMappingApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /003-helloworld-restcontroller/src/main/java/com/stonie/springnotes/RestControllerApp.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestControllerApp { 8 | 9 | public static void main( String[] args ) { 10 | SpringApplication.run(RestControllerApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /006-helloworld-configurationproperties/src/main/java/com/stonie/springnotes/config/StonieConfig.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes.config; 2 | 3 | import com.stonie.springnotes.properties.StonieProperties; 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | @EnableConfigurationProperties(StonieProperties.class) 9 | public class StonieConfig { 10 | } 11 | -------------------------------------------------------------------------------- /006-helloworld-configurationproperties/src/main/java/com/stonie/springnotes/ConfigurationPropertiesApp.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ConfigurationPropertiesApp { 8 | 9 | public static void main( String[] args ) { 10 | SpringApplication.run(ConfigurationPropertiesApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /004-helloworld-springbootapplication/src/main/java/com/stonie/springnotes/SpringBootApp.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.context.annotation.ComponentScan; 6 | 7 | @EnableAutoConfiguration 8 | @ComponentScan 9 | public class SpringBootApp { 10 | 11 | public static void main( String[] args ) { 12 | SpringApplication.run(SpringBootApp.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /005-helloworld-configuration/src/main/java/com/stonie/springnotes/config/TestConfig.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes.config; 2 | 3 | import com.stonie.springnotes.service.TestService; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Scope; 7 | 8 | @Configuration 9 | public class TestConfig { 10 | 11 | //@Bean(initMethod = "init", destroyMethod = "destroy") 12 | @Bean 13 | @Scope("prototype") 14 | public TestService testService() { 15 | return new TestService(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /006-helloworld-configurationproperties/README.md: -------------------------------------------------------------------------------- 1 | # 006-helloworld-configurationproperties 2 | 3 | 这是一个使用 `spring-boot-starter-web` 构建的最简单的 Spring Boot Web 项目,学习 `@ConfigurationProperties` 注解的用法。 4 | 5 | ## 知识点 6 | 7 | ### 使用 @ConfigurationProperties 的两种方式 8 | 9 | 1. @Configuration + @EnableConfigurationProperties 10 | 2. @Component 11 | 12 | ### spring-boot-configuration-processor 13 | 14 | ## 相关引用 15 | 16 | ### 依赖 17 | 18 | * spring-boot-starter-parent 19 | * spring-boot-starter-web 20 | * spring-boot-maven-plugin 21 | * spring-boot-configuration-processor *[New]* 22 | 23 | ### 类 24 | 25 | * SpringApplication 26 | 27 | ### 注解 28 | 29 | * SpringBootApplication 30 | * RequestMapping 31 | * RestController 32 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.stonie.springnotes 6 | spring-notes 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 001-helloworld 11 | 002-helloworld-requestmapping 12 | 003-helloworld-restcontroller 13 | 004-helloworld-springbootapplication 14 | 005-helloworld-configuration 15 | 006-helloworld-configurationproperties 16 | 17 | -------------------------------------------------------------------------------- /006-helloworld-configurationproperties/src/main/java/com/stonie/springnotes/ConfigurationPropertiesController.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import com.stonie.springnotes.properties.StonieProperties; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class ConfigurationPropertiesController { 9 | 10 | private StonieProperties stonieProperties; 11 | 12 | public ConfigurationPropertiesController(StonieProperties stonieProperties) { 13 | this.stonieProperties = stonieProperties; 14 | } 15 | 16 | @RequestMapping("/") 17 | public String index() { 18 | return String.format("%s %s!", 19 | this.stonieProperties.getHelloTitle(), 20 | this.stonieProperties.getHelloName()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /006-helloworld-configurationproperties/src/main/java/com/stonie/springnotes/properties/StonieProperties.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes.properties; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | //@Component 7 | @ConfigurationProperties(prefix = "com.stonie") 8 | public class StonieProperties { 9 | 10 | private String helloTitle; 11 | private String helloName; 12 | 13 | public String getHelloTitle() { 14 | return helloTitle; 15 | } 16 | 17 | public void setHelloTitle(String helloTitle) { 18 | this.helloTitle = helloTitle; 19 | } 20 | 21 | public String getHelloName() { 22 | return helloName; 23 | } 24 | 25 | public void setHelloName(String helloName) { 26 | this.helloName = helloName; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /005-helloworld-configuration/src/main/java/com/stonie/springnotes/service/TestService.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes.service; 2 | 3 | import javax.annotation.PostConstruct; 4 | import javax.annotation.PreDestroy; 5 | 6 | public class TestService { 7 | 8 | public Integer add(Integer a, Integer b) { 9 | if (a == null || b == null) { 10 | return 0; 11 | } 12 | return a + b; 13 | } 14 | 15 | public Integer sub(Integer a, Integer b) { 16 | if (a == null || b == null) { 17 | return 0; 18 | } 19 | return a - b; 20 | } 21 | 22 | @PostConstruct 23 | private void init() { 24 | System.out.println("initializing test service..."); 25 | } 26 | 27 | @PreDestroy 28 | private void destroy() { 29 | System.out.println("destroying test service..."); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /003-helloworld-restcontroller/README.md: -------------------------------------------------------------------------------- 1 | # 003-helloworld-restcontroller 2 | 3 | 这是一个使用 `spring-boot-starter-web` 构建的最简单的 Spring Boot Web 项目,主要学习 `@RestController` 的用法以及 `@RestController` 和 `@Controller` 的区别。 4 | 5 | ## 知识点 6 | 7 | `@RestController` 注解是 `@Controller` 和 `@ResponseBody` 两个注解的结合。在 Spring 4.0 中被引入,用于更方便的创建 Restful 接口,省去了在每个方法上加 `@ResponseBody` 的麻烦。 8 | 9 | ``` 10 | @Target(ElementType.TYPE) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Documented 13 | @Controller 14 | @ResponseBody 15 | public @interface RestController { 16 | } 17 | ``` 18 | 19 | ## 相关引用 20 | 21 | ### 依赖 22 | 23 | * spring-boot-starter-parent 24 | * spring-boot-starter-web 25 | * spring-boot-maven-plugin 26 | 27 | ### 类 28 | 29 | * SpringApplication 30 | 31 | ### 注解 32 | 33 | * SpringBootApplication 34 | * RequestMapping 35 | * RestController 36 | 37 | * Controller [*New*] 38 | * ResponseBody [*New*] 39 | 40 | ## 参考 41 | 42 | 1. [The Spring @Controller and @RestController Annotations](https://www.baeldung.com/spring-controller-vs-restcontroller) 43 | -------------------------------------------------------------------------------- /003-helloworld-restcontroller/src/main/java/com/stonie/springnotes/RestfulController.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | @RestController 10 | public class RestfulController { 11 | 12 | /** 13 | * curl -X GET -iv http://localhost:8080/restful/string 14 | * 注意请求响应,Content-Type: text/plain;charset=UTF-8 15 | */ 16 | @RequestMapping("/restful/string") 17 | public String restfulString() { 18 | return "restfulString"; 19 | } 20 | 21 | /** 22 | * curl -X GET -i http://localhost:8080/restful/object 23 | * 注意请求响应:Content-Type: application/json 24 | */ 25 | @RequestMapping("/restful/object") 26 | public Object restfulObject() { 27 | Map map = new HashMap(); 28 | map.put("hello", "world"); 29 | return map; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /005-helloworld-configuration/src/main/java/com/stonie/springnotes/ConfigurationController.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import com.stonie.springnotes.service.TestService; 4 | import org.springframework.context.annotation.Scope; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @Scope("prototype") 10 | public class ConfigurationController { 11 | 12 | private TestService testService; 13 | 14 | public ConfigurationController(TestService testService) { 15 | this.testService = testService; 16 | System.out.println(this.testService); 17 | } 18 | 19 | @RequestMapping("/") 20 | public String index() { 21 | return "Hello World!"; 22 | } 23 | 24 | @RequestMapping("/add") 25 | public Integer add(Integer a, Integer b) { 26 | return testService.add(a, b); 27 | } 28 | 29 | @RequestMapping("/sub") 30 | public Integer sub(Integer a, Integer b) { 31 | return testService.sub(a, b); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /001-helloworld/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.stonie.springnotes 6 | 001-helloworld 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 001-helloworld 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 2.3.1.RELEASE 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /005-helloworld-configuration/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.stonie.springnotes 6 | 005-helloworld-configuration 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 005-helloworld-configuration 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 2.3.1.RELEASE 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /002-helloworld-requestmapping/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.stonie.springnotes 6 | 002-helloworld-requestmapping 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 002-helloworld-requestmapping 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 2.3.1.RELEASE 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /003-helloworld-restcontroller/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.stonie.springnotes 6 | 003-helloworld-restcontroller 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 003-helloworld-restcontroller 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 2.3.1.RELEASE 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /004-helloworld-springbootapplication/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.stonie.springnotes 6 | 004-helloworld-springbootapplication 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 004-helloworld-springbootapplication 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 2.3.1.RELEASE 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-maven-plugin 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /003-helloworld-restcontroller/src/main/java/com/stonie/springnotes/NormalController.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.ResponseBody; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | @Controller 11 | public class NormalController { 12 | 13 | /** 14 | * curl -X GET -iv http://localhost:8080/normal/string 15 | * 注意请求响应,Content-Type: text/plain;charset=UTF-8 16 | */ 17 | @RequestMapping("/normal/string") 18 | public @ResponseBody String normalString() { 19 | return "normalString"; 20 | } 21 | 22 | /** 23 | * curl -X GET -i http://localhost:8080/normal/object 24 | * 注意请求响应:Content-Type: application/json 25 | */ 26 | @RequestMapping("/normal/object") 27 | public @ResponseBody Object normalObject() { 28 | Map map = new HashMap(); 29 | map.put("hello", "world"); 30 | return map; 31 | } 32 | 33 | /** 34 | * This is a 404 request, because there is no views named 'normalStringWithoutResponseBody' 35 | * curl -X GET -iv http://localhost:8080/normal/string-without-response-body 36 | */ 37 | @RequestMapping("/normal/string-without-response-body") 38 | public String normalStringWithoutResponseBody() { 39 | return "normalStringWithoutResponseBody"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /001-helloworld/README.md: -------------------------------------------------------------------------------- 1 | # 001-helloword 2 | 3 | 这是一个使用 `spring-boot-starter-web` 构建的最简单的 Spring Boot Web 项目,启动后访问 `http://localhost:8080/` 显示 `Hello World!`,通过这个工程学习如何快速构建 Spring Boot Web 项目。 4 | 5 | ## 知识点 6 | 7 | 首先在 `pom.xml` 中添加依赖 `spring-boot-starter-web`: 8 | 9 | ``` 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-web 14 | 15 | 16 | ``` 17 | 18 | 然后添加两个类:`HelloWorldApp` 为入口类,包含一个 `main` 方法,`HelloWorldController` 为控制器类,用于处理 HTTP 请求。 19 | 20 | ``` 21 | @SpringBootApplication 22 | public class HelloWorldApp { 23 | public static void main( String[] args ) { 24 | SpringApplication.run(HelloWorldApp.class, args); 25 | } 26 | } 27 | ``` 28 | 29 | `HelloWorldApp` 和普通的 Java 入口类有两个主要区别,一个是类上添加了 `@SpringBootApplication` 注解,用于开启 Spring Boot 的自动配置特性以及扫描项目中的 Spring Bean。另一个区别是在 `main` 方法中通过调用 `SpringApplication.run()` 启动 Spring Boot 应用。 30 | 31 | ``` 32 | @RestController 33 | public class HelloWorldController { 34 | @RequestMapping("/") 35 | public String index() { 36 | return "Hello World!"; 37 | } 38 | } 39 | ``` 40 | 41 | 另外,我们在 `HelloWorldController` 类上加上 `@RestController` 注解,用于标识这个类为控制器类,并在 `index()` 方法上加上 `@RequestMapping` 注解,表示这是一条请求映射,将路径为 `/` 的 URL 请求映射到 `index()` 方法。 42 | 43 | ## 相关引用 44 | 45 | ### 依赖 46 | 47 | * spring-boot-starter-parent 48 | * spring-boot-starter-web 49 | * spring-boot-maven-plugin 50 | 51 | ### 类 52 | 53 | * SpringApplication 54 | 55 | ### 注解 56 | 57 | * SpringBootApplication 58 | * RequestMapping 59 | * RestController 60 | -------------------------------------------------------------------------------- /006-helloworld-configurationproperties/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.stonie.springnotes 6 | 006-helloworld-configurationproperties 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | 006-helloworld-configurationproperties 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 2.3.1.RELEASE 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-configuration-processor 31 | true 32 | 33 | 34 | 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-maven-plugin 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /005-helloworld-configuration/README.md: -------------------------------------------------------------------------------- 1 | # 005-helloworld-configuration 2 | 3 | 这是一个使用 `spring-boot-starter-web` 构建的最简单的 Spring Boot Web 项目,主要学习 `@Configuration` 和 `@Bean` 注解。 4 | 5 | ## 知识点 6 | 7 | 在 Spring 3 之前,都是使用 XML 文件来定义 Bean,像下面这样: 8 | 9 | ``` 10 | 11 | 15 | 16 | 17 | 18 | 19 | ``` 20 | 21 | 从 Spring 3 开始,我们可以使用 Java 代码来定义 Bean,这被称为 `Java Config`。只要将 `@Configuration` 注解放在某个类上,就可以在这个类中定义一个或多个 Bean。 22 | 23 | ``` 24 | @Configuration 25 | public class TestConfig { 26 | @Bean 27 | public TestService testService() { 28 | return new TestService(); 29 | } 30 | } 31 | ``` 32 | 33 | ## Bean 的生命周期 34 | 35 | 可以使用基于 Java 的配置来管理 Bean 的生命周期,`@Bean` 支持两种属性,即 `initMethod` 和 `destroyMethod`,这些属性可用于定义生命周期方法。在实例化 Bean 或即将销毁它时,容器便可调用生命周期方法。生命周期方法也称为回调方法,因为它将由容器调用。使用 `@Bean` 注释注册的 Bean 也支持 JSR-250 规定的标准 `@PostConstruct` 和 `@PreDestroy` 注解。 36 | 37 | ## `@Scope` 注解 38 | 39 | * singleton:默认值,单例 40 | * prototype:多例(原型作用域) 41 | * request:创建对象,把对象放到 request 域里 42 | * session:创建对象,把对象放到 session 域里 43 | * globalSession:创建对象,把对象放到 globalSession 域里 44 | 45 | ## 相关引用 46 | 47 | ### 依赖 48 | 49 | * spring-boot-starter-parent 50 | * spring-boot-starter-web 51 | * spring-boot-maven-plugin 52 | 53 | ### 类 54 | 55 | * SpringApplication 56 | 57 | ### 注解 58 | 59 | * SpringBootApplication 60 | * RequestMapping 61 | * RestController 62 | 63 | * Configuration [*New*] 64 | * Bean [*New*] 65 | * Scope [*New*] 66 | * PostConstruct [*New*] 67 | * PreDestroy [*New*] 68 | -------------------------------------------------------------------------------- /002-helloworld-requestmapping/README.md: -------------------------------------------------------------------------------- 1 | # 002-helloworld-requestmapping 2 | 3 | 这是一个使用 `spring-boot-starter-web` 构建的最简单的 Spring Boot Web 项目,主要学习 `RequestMapping` 的用法。 4 | 5 | ## 知识点 6 | 7 | `RequestMapping` 注解可以用于类和方法上,主要作用是将 Web 请求映射到某个 Controller 的某个方法上。 8 | 9 | ``` 10 | @Target({ElementType.TYPE, ElementType.METHOD}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Documented 13 | @Mapping 14 | public @interface RequestMapping { 15 | } 16 | ``` 17 | 18 | ### `@RequestMapping` 基本用法 19 | 20 | 1. path 21 | 22 | ``` 23 | @RequestMapping(path = "/path-method-all") 24 | ``` 25 | 26 | 2. method 27 | 28 | ``` 29 | @RequestMapping(path = "/path-method-post", method = RequestMethod.POST) 30 | ``` 31 | 32 | 3. headers 33 | 34 | ``` 35 | @RequestMapping(path = "/path-method-post-headers", method = RequestMethod.POST, headers = "key=value") 36 | ``` 37 | 38 | 4. consumes 39 | 40 | ``` 41 | @RequestMapping(path = "/path-method-post-consumes", method = RequestMethod.POST, consumes = "application/json") 42 | ``` 43 | 44 | 5. produces 45 | 46 | ``` 47 | @RequestMapping(path = "/path-method-post-produces", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 48 | ``` 49 | 50 | ### `@RequestMapping` 高级用法 51 | 52 | 1. Multiple Path 53 | 54 | ``` 55 | @RequestMapping(path = { "/path-a", "/path-b" }, method = RequestMethod.GET) 56 | ``` 57 | 58 | 2. Multiple HTTP Method 59 | 60 | ``` 61 | @RequestMapping(path = "/path-method-multiple", method = { RequestMethod.POST, RequestMethod.PUT }) 62 | ``` 63 | 64 | ### `@PathVariable` 注解 65 | 66 | 1. `@PathVariable` 基本用法 67 | 68 | ``` 69 | @RequestMapping(path = "/path-method-get/{id}", method = RequestMethod.GET) 70 | public String pathMethodGet(@PathVariable String id) { 71 | } 72 | ``` 73 | 74 | 2. `@PathVariable` 正则表达式 75 | 76 | ``` 77 | @RequestMapping(path = "/path-method-get-regex/{id:[\\d]+}", method = RequestMethod.GET) 78 | public String pathMethodGetRegex(@PathVariable String id) { 79 | } 80 | ``` 81 | 82 | ### `@RequestParam` 注解 83 | 84 | 1. `@RequestParam` 基本用法 85 | 86 | ``` 87 | @RequestMapping(path = "/path-method-get-param", method = RequestMethod.GET) 88 | public String pathMethodGetParam(@RequestParam String id) { 89 | } 90 | ``` 91 | 92 | 2. `@RequestParam` 默认值 93 | 94 | ``` 95 | @RequestMapping(path = "/path-method-get-param-default", method = RequestMethod.GET) 96 | public String pathMethodGetParamDefault(@RequestParam(defaultValue = "1") String id) { 97 | } 98 | ``` 99 | 100 | 3. `@RequestParam` 可选参数 101 | 102 | ``` 103 | @RequestMapping(path = "/path-method-get-param-required", method = RequestMethod.GET) 104 | public String pathMethodGetParamRequired(@RequestParam String a, @RequestParam(required = false) String b) { 105 | } 106 | ``` 107 | 108 | ### `@RequestMapping` 简写 109 | 110 | * @GetMapping 111 | * @PostMapping 112 | * @PutMapping 113 | * @DeleteMapping 114 | * @PatchMapping 115 | 116 | ``` 117 | @GetMapping(path = "/path-method-get-simple") 118 | public String pathMethodGetSimple() { 119 | } 120 | ``` 121 | 122 | ## 相关引用 123 | 124 | ### 依赖 125 | 126 | * spring-boot-starter-parent 127 | * spring-boot-starter-web 128 | * spring-boot-maven-plugin 129 | 130 | ### 类 131 | 132 | * SpringApplication 133 | 134 | ### 注解 135 | 136 | * SpringBootApplication 137 | * RequestMapping 138 | * RestController 139 | 140 | * GetMapping [*New*] 141 | * PostMapping [*New*] 142 | * PutMapping [*New*] 143 | * DeleteMapping [*New*] 144 | * PatchMapping [*New*] 145 | 146 | * PathVariable [*New*] 147 | * RequestParam [*New*] 148 | 149 | ### 枚举 150 | 151 | * RequestMethod [*New*] 152 | 153 | ## 参考 154 | 155 | 1. [Spring @RequestMapping | Baeldung](https://www.baeldung.com/spring-requestmapping) 156 | -------------------------------------------------------------------------------- /004-helloworld-springbootapplication/README.md: -------------------------------------------------------------------------------- 1 | # 004-helloworld-springbootapplication 2 | 3 | 这是一个使用 `spring-boot-starter-web` 构建的最简单的 Spring Boot Web 项目,主要学习 `@SpringBootApplication` 注解的原理。 4 | 5 | ## 知识点 6 | 7 | `@SpringBootApplication` 注解的定义如下: 8 | 9 | ``` 10 | @Target({ElementType.TYPE}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Documented 13 | @Inherited 14 | @SpringBootConfiguration 15 | @EnableAutoConfiguration 16 | @ComponentScan( 17 | excludeFilters = {@Filter( 18 | type = FilterType.CUSTOM, 19 | classes = {TypeExcludeFilter.class} 20 | ), @Filter( 21 | type = FilterType.CUSTOM, 22 | classes = {AutoConfigurationExcludeFilter.class} 23 | )} 24 | ) 25 | public @interface SpringBootApplication { 26 | } 27 | ``` 28 | 29 | 其中 `@Target` 用于说明这个注解出现的位置,`ElementType.TYPE` 表示只能作用于类上,类似的,如果是 `ElementType.METHOD` 表示注解作用于方法上,如果是 `ElementType.FIELD` 表示注解作用于域上。 30 | 31 | `@Retention` 用于说明注解的生命周期,注解有三个生命周期:`RetentionPolicy.SOURCE` 表示注解只保留在源文件,当 Java 文件编译成 class 文件时,注解被遗弃;`RetentionPolicy.CLASS` 表示注解保留到 class 文件,当 JVM 加载 class 时注解被遗弃;`RetentionPolicy.RUNTIME` 表示注解在 JVM 加载 class 之后仍然保留,被称为运行时注解。这里的 `@SpringBootApplication` 就是运行时注解。 32 | 33 | `@Documented` 表示这个注解的信息会被包括在 javadoc 生成的文档中。 34 | 35 | `@Inherited` 表示这个注解是否被子类继承,子类会继承父类使用的注解中被 `@Inherited` 修饰的注解。 36 | 37 | 上面这四个注解都是在自定义注解时非常常用的,但是要实现 `@SpringBootApplication` 注解的功能,最关键的还是下面这三个注解: 38 | 39 | * `@SpringBootConfiguration` 40 | * `@EnableAutoConfiguration` 41 | * `@ComponentScan` 42 | 43 | 其中 `@SpringBootConfiguration` 注解的定义如下: 44 | 45 | ``` 46 | @Target({ElementType.TYPE}) 47 | @Retention(RetentionPolicy.RUNTIME) 48 | @Documented 49 | @Configuration 50 | public @interface SpringBootConfiguration { 51 | } 52 | ``` 53 | 54 | 可以看到 `@SpringBootConfiguration` 实际上就是一个 `@Configuration` 注解,用于定义配置类,可替换 xml 配置文件,被注解的类内部包含有一个或多个被 `@Bean` 注解的方法,这些方法将会被 `AnnotationConfigApplicationContext` 或 `AnnotationConfigWebApplicationContext` 类进行扫描,并用于构建 Bean 定义,初始化 Spring 容器。在我们这个例子中,`SpringBootApp` 类里并没有定义 Bean,所以这个注解可以忽略。 55 | 56 | `@EnableAutoConfiguration` 注解的定义如下: 57 | 58 | ``` 59 | @Target({ElementType.TYPE}) 60 | @Retention(RetentionPolicy.RUNTIME) 61 | @Documented 62 | @Inherited 63 | @AutoConfigurationPackage 64 | @Import({AutoConfigurationImportSelector.class}) 65 | public @interface EnableAutoConfiguration { 66 | } 67 | ``` 68 | 69 | 其中 `@AutoConfigurationPackage` 的定义如下: 70 | 71 | ``` 72 | @Target({ElementType.TYPE}) 73 | @Retention(RetentionPolicy.RUNTIME) 74 | @Documented 75 | @Inherited 76 | @Import({Registrar.class}) 77 | public @interface AutoConfigurationPackage { 78 | } 79 | ``` 80 | 81 | 可以看出 `@EnableAutoConfiguration` 注解实际上是由两个 `@Import` 注解组成的。`@Import` 可以将某个类注入 Spring 容器中,一般来说有四种用法: 82 | 83 | 1. 注入带 `@Configuration` 的配置类 84 | 1. 注入普通类(4.2 之后的版本支持) 85 | 2. `ImportSelector` 86 | 3. `ImportBeanDefinitionRegistrar` 87 | 88 | 通过查看 `AutoConfigurationImportSelector` 和 `Registrar` 的源码,可以看出它们分别对应 `ImportSelector` 和 `ImportBeanDefinitionRegistrar` 两种方式。 89 | 90 | ``` 91 | public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { 92 | } 93 | ``` 94 | 95 | ``` 96 | static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { 97 | } 98 | ``` 99 | 100 | 最后一个 `@ComponentScan` 注解,它告诉 Spring 从哪里去找带 `@Component` 的类(包括 `@Controller`,`@Service`,`@Repository` 等),然后将其注入到 Spring 容器中,它有下面几种用法: 101 | 102 | * 自定扫描路径下边带有 `@Controller`,`@Service`,`@Repository`,`@Component` 注解加入 Spring 容器 103 | * 通过 `includeFilters` 加入扫描路径下没有以上注解的类加入 Spring 容器 104 | * 通过 `excludeFilters` 过滤出不用加入 Spring 容器的类 105 | 106 | 通过上面的分析,我们可以改动下 `001-helloworld` 项目,将 `SpringBootApp` 上面的 `@SpringBootApplication` 注解改成 `@EnableAutoConfiguration` 和 `@ComponentScan`,程序一样可以跑起来。 107 | 108 | ``` 109 | @EnableAutoConfiguration 110 | @ComponentScan 111 | public class SpringBootApp { 112 | } 113 | ``` 114 | 115 | ## 相关引用 116 | 117 | ### 依赖 118 | 119 | * spring-boot-starter-parent 120 | * spring-boot-starter-web 121 | * spring-boot-maven-plugin 122 | 123 | ### 类 124 | 125 | * SpringApplication 126 | 127 | * AutoConfigurationImportSelector [*New*] 128 | * Registrar [*New*] 129 | 130 | ### 注解 131 | 132 | * SpringBootApplication 133 | * RequestMapping 134 | * RestController 135 | 136 | * Target [*New*] 137 | * Retention [*New*] 138 | * Documented [*New*] 139 | * Inherited [*New*] 140 | * SpringBootConfiguration [*New*] 141 | * @Configuration [*New*] 142 | * EnableAutoConfiguration [*New*] 143 | * AutoConfigurationPackage [*New*] 144 | * Import [*New*] 145 | * ComponentScan [*New*] 146 | -------------------------------------------------------------------------------- /002-helloworld-requestmapping/src/main/java/com/stonie/springnotes/RequestMappingController.java: -------------------------------------------------------------------------------- 1 | package com.stonie.springnotes; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.PathVariable; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class RequestMappingController { 12 | 13 | /** 14 | * curl -X GET -i http://localhost:8080/path-method-all 15 | * curl -X POST -i http://localhost:8080/path-method-all 16 | */ 17 | @RequestMapping(path = "/path-method-all") 18 | public String pathMethodAll() { 19 | return "pathMethodAll"; 20 | } 21 | 22 | /** 23 | * curl -X POST -i http://localhost:8080/path-method-post 24 | */ 25 | @RequestMapping(path = "/path-method-post", method = RequestMethod.POST) 26 | public String pathMethodPost() { 27 | return "pathMethodPost"; 28 | } 29 | 30 | /** 31 | * curl -X POST -H "key:value" -i http://localhost:8080/path-method-post-headers 32 | */ 33 | @RequestMapping(path = "/path-method-post-headers", method = RequestMethod.POST, headers = "key=value") 34 | public String pathMethodPostHeaders() { 35 | return "pathMethodPostHeaders"; 36 | } 37 | 38 | /** 39 | * curl -X POST -H "Content-Type:application/json" -i http://localhost:8080/path-method-post-consumes 40 | */ 41 | @RequestMapping(path = "/path-method-post-consumes", method = RequestMethod.POST, consumes = "application/json") 42 | public String pathMethodPostConsumes() { 43 | return "pathMethodPostConsumes"; 44 | } 45 | 46 | /** 47 | * curl -X POST -iv http://localhost:8080/path-method-post-produces 48 | * 49 | * 指定 HTTP 响应 Content-Type: application/json;charset=UTF-8 50 | * 如果不指定 produces,默认为 Content-Type: text/plain;charset=UTF-8 51 | */ 52 | @RequestMapping(path = "/path-method-post-produces", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 53 | public String pathMethodPostProduces() { 54 | return "pathMethodPostProduces"; 55 | } 56 | 57 | /** 58 | * curl -X GET -i http://localhost:8080/path-a 59 | * curl -X GET -i http://localhost:8080/path-b 60 | */ 61 | @RequestMapping(path = { "/path-a", "/path-b" }, method = RequestMethod.GET) 62 | public String pathMultiple() { 63 | return "pathMultiple"; 64 | } 65 | 66 | /** 67 | * This is OK: 68 | * curl -X POST -i http://localhost:8080/path-method-multiple 69 | * curl -X PUT -i http://localhost:8080/path-method-multiple 70 | * This is not OK: 71 | * curl -X GET -i http://localhost:8080/path-method-multiple 72 | */ 73 | @RequestMapping(path = "/path-method-multiple", method = { RequestMethod.POST, RequestMethod.PUT }) 74 | public String methodMultiple() { 75 | return "methodMultiple"; 76 | } 77 | 78 | /** 79 | * curl -X GET -i http://localhost:8080/path-method-get/1 80 | */ 81 | @RequestMapping(path = "/path-method-get/{id}", method = RequestMethod.GET) 82 | public String pathMethodGet(@PathVariable String id) { 83 | return "pathMethodGet: " + id; 84 | } 85 | 86 | /** 87 | * This is OK: 88 | * curl -X GET -i http://localhost:8080/path-method-get-regex/123 89 | * This is not OK: 90 | * curl -X GET -i http://localhost:8080/path-method-get-regex/hello 91 | */ 92 | @RequestMapping(path = "/path-method-get-regex/{id:[\\d]+}", method = RequestMethod.GET) 93 | public String pathMethodGetRegex(@PathVariable String id) { 94 | return "pathMethodGetRegex: " + id; 95 | } 96 | 97 | /** 98 | * curl -X GET -i http://localhost:8080/path-method-get-param?id=1 99 | */ 100 | @RequestMapping(path = "/path-method-get-param", method = RequestMethod.GET) 101 | public String pathMethodGetParam(@RequestParam String id) { 102 | return "pathMethodGetParam: " + id; 103 | } 104 | 105 | /** 106 | * curl -X GET -i http://localhost:8080/path-method-get-param-default 107 | * curl -X GET -i http://localhost:8080/path-method-get-param-default?id=5 108 | */ 109 | @RequestMapping(path = "/path-method-get-param-default", method = RequestMethod.GET) 110 | public String pathMethodGetParamDefault(@RequestParam(defaultValue = "1") String id) { 111 | return "pathMethodGetParamDefault: " + id; 112 | } 113 | 114 | /** 115 | * This is OK: 116 | * curl -X GET -i "http://localhost:8080/path-method-get-param-required?a=1" 117 | * curl -X GET -i "http://localhost:8080/path-method-get-param-required?a=1&b=2" 118 | * This is not OK: 119 | * curl -X GET -i "http://localhost:8080/path-method-get-param-required?b=2" 120 | */ 121 | @RequestMapping(path = "/path-method-get-param-required", method = RequestMethod.GET) 122 | public String pathMethodGetParamRequired( 123 | @RequestParam String a, @RequestParam(required = false) String b) { 124 | return "pathMethodGetParamRequired: " + a + ", " + b; 125 | } 126 | 127 | /** 128 | * curl -X GET -i http://localhost:8080/path-method-get-simple 129 | */ 130 | @GetMapping(path = "/path-method-get-simple") 131 | public String pathMethodGetSimple() { 132 | return "pathMethodGetSimple"; 133 | } 134 | } 135 | --------------------------------------------------------------------------------