---
# System prepended metadata

title: Spring Boot

---

# Spring Boot

學習資源: https://spring.io/
快速建立專案: https://start.spring.io/


## 建立 Spring Boot 開發環境
```java=
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
// @RestController 註解告訴Spring這段代碼描述了一個端點，該端點可以在web上運用。
@RestController
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
	// hello() 我們添加的方法採用一個 value = name。 然後將此參數與單字結合。
	// GetMapping("/hello") 告訴 Spring 使用我們的hello發送請求到 http://localhost:8080/hello
	// @RequestParam 告訴 Spring 再請求中期望一個名稱值，但如果不存在，它將默認使用單字 World。
	@GetMapping("/hello")
	public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
		// %s 為 string
		return String.format("Hello %s!", name);
	}
}
```

使用以下指令來嘗試跑跑看Web
```
mvnw spring-boot:run
```

成功跑起來！！
![](https://i.imgur.com/yrMVdVt.png)

## Springboot helloworld

demoApplication.java
```java=
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		// Spring 應用啟動起來
		SpringApplication.run(DemoApplication.class,args);
	}
}
```

HelloController.java
```java=
package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HellController {

    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {
        return "Hello World!";
    }
}
```

成功執行的畫面 
![](https://i.imgur.com/mBjf0zY.png)

## 主程序類, 主入口類 (自動架構)

學習網站: https://www.youtube.com/watch?v=4t_xM7FefWM&list=PLmOn9nNkQxJEFsK2HVO9-WA55Z7LZ2N0S&index=8

@**SpringBootApplication**: Spring Boot 應用標住在某個類上說明這個類是Spring Boot的主配置類，SpringBoot就應該運行這個類的main方法啟動SpringBoot應用。

```java=
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
```
@SpringBootConfiguration: Spring Boot的配置類:
- 標住在某個類上，表示這是一個Spring Boot配置類。 
- @Configuration: 配置類上標註這個註解。
    -  配置類 ----- 配置文件，配置類也是容器中的一個組件，@Componet

@EnableAutoConfiguration: 開啟自動配置功能:
- 以前我們需要配置的東西，Spring Boot幫我們自動配置， @EnableAutoConfiguration 告訴Spring Boot開啟自動配置功能，這樣配置才會生效。
@AutoConfigurationPackage: 自動配置包
- @Import({AutoConfigurationImportSelector.class})
- Spring的底層註解@Import,給容器中導入一個組件。導入的組件由AutoConfigurationExcludeFilter.class
- 將主配置類(@SpringBootApplication標註的類)的所在包以及下面所有子包裡面所有組件掃描到Spring容器



## 建立 RESTful Web 服務
參考網頁: https://spring.io/guides/gs/rest-service/
```java=
package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();
    // GetMapping("/hello") 確保 HTTP GET 請求到 /greeting 被映射到 greeting() 方法
    // 也有很多種 HTTP 不同方式的請求例如: POST REQUEST..
    // @PostMapping for POST 、 @RequestMapping(method=GET) for GET。
    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name" , defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(),String.format(template,name));
    }
}
```

好像是 8080 port有用過的關係，而網頁說的是沒有利用GetMapping映射。
![](https://i.imgur.com/EoIa7nG.png)

在後來重開機之後，不知道為甚麼又成功跑出來了
![](https://i.imgur.com/Y2RePp9.png)

測試服務:
網址: http://localhost:8080/greeting?name=user
![](https://i.imgur.com/aRSuuCc.png)
因為我在 Greeting.java 建立了一個 Greeting 的函式，而這個函式主要回傳 id 以及 字串 

Greeting.java
```java=
package com.example.demo;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }
    public long getId() {
        return id;
    }
    public String getContent() {
        return content;
    }
}
```

而我在 GreetingController.java 回傳了 Greeting 的建構子，因此我的顯示內容會像蓋房子一樣當我 RequestParam 的 name 稍微更動，而我的 id 也會因此不同。
GreetingController.java
```java=
package com.example.demo;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

@SpringBootApplication
@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();
    // GetMapping("/hello") 確保 HTTP GET 請求到 /greeting 被映射到 greeting() 方法
    // 也有很多種 HTTP 不同方式的請求例如: POST REQUEST..
    // @PostMapping for POST 、 @RequestMapping(method=GET) for GET。
    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name" , defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(),String.format(template,name));
    }
}
```

id 會一直增加因為會不斷新增新的 ID
![](https://i.imgur.com/wmZm2Yk.png)
![](https://i.imgur.com/N9NO0mG.png)

## Spring Boot 調用 Python腳本運行

學習網站: https://blog.csdn.net/qq_44648936/article/details/123593075

調用 Java Runtime.getRuntime() 方法，以達到成功執行 python 的檔案。

GreetingController.java
```java=
package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;

@RestController
@RequestMapping("/face")
public class GreetingController {

    @Autowired
    private FaceService faceService;

    @RequestMapping("/face")
    public void face() throws IOException {
        faceService.faceRecognition();
    }

}

```

FaceService.java
```java=
package com.example.demo;

import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

@Service
public class FaceService {

    // 前面一半是本地環境下的python的啟動文件地址, 後面一半是要執行的python腳本地址
    public void faceRecognition() throws IOException {
        String[] arguments = new String[] {"C:\\\\Program Files (x86)\\\\Microsoft Visual Studio\\\\Shared\\\\Python36_64\\\\python.exe\"", "C:\\Users\\YouKlike\\Code\\Spring Boot\\main.py"};

        Process process;

        try {
            process = Runtime.getRuntime().exec(arguments); // 執行py檔案
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            new InputStreamReader(process.getInputStream());
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
            in.close();
            int re = process.waitFor();
            System.out.println(re);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
```

連線失敗Orz
![](https://i.imgur.com/WtLzk0S.png)

我猜應該是已經執行過了所以可能要重開機才能生效

### SpringBoot Initializer 使用向導快速創建Spring Boot應用
IDE都支持使用Spring的項目創建向導快速創建一個Spring Boot項目

### Spring Boot 配置 yaml簡介

- Spring Boot使用一個全局的配置文件，配置文件名是固定的:
    - application.properties
    - application.yml 
配置文件的作用: 修改SpringBoot自動配置的默認值:
SpringBoot在底層都給我們自動配置好了

YMAL (YMAL Ain't Markup Language)

標記語言:
- 以前配置文件，大多都使用的是 xxx.xml文件:
- YMAL