├── 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 |
--------------------------------------------------------------------------------