SpringBoot之路(一)之初識SpringBoot

cmazxiaoma發表於2019-03-01

####前言
Spring Boot是用來簡化Spring應用初始搭建以及開發過程的全新框架,被認為是SpringMVC的接班人,和微服務緊密聯絡在一起。Spring Boot 簡單例項Demo

####SpringMVC 的優缺點

  • 優點:

    • Spring Boot適合快速開發,適合構建微服務系統。封裝了經常使用的元件,比如MyBatis, Hibernate, MongoDB等。
    • Java的配置,簡單方便。
    • 配置Maven等構建工具後,java -jar進行部署比較簡單。
    • Spring Boot對自定義十分友好,可以配置在application.yml或者Config類,Spring Boot的整體思想是有自定義的話,自定義優先,否則走預設配置。
    • Spring Boot使編碼,配置,部署,監控變得簡單起來。
  • 缺點:

    • 太方便,使得沒有經驗的新手根本不知道Spring Boot 底層到底幹了什麼。整合度較高,使用過程中不容易瞭解底層。
    • 相關學習文件少, 坑多。

####第一個Spring Boot的應用

  1. 首先建立一個New Project,要選擇Spring Initializr, 然後Choose Initializr Service URL應該選擇Custom, 正確的連結應該是http://start.spring.io/,而不是https://start.spring.io/https會造成我們訪問失敗!
Paste_Image.png

2.相關配置,Type我們選擇Maven Project

Paste_Image.png

3.選擇Web就行了。另外Spring Boot的版本是1.5.8

Paste_Image.png

4.Finished。大功告成!

Paste_Image.png

5.由於預設的setting.xml配置,導致我們從遠端下jar實在是太慢,所以我們要修改.m2下面的setting.xml檔案,同時將setting.xml原本指向C:UsersAdministrator.m2
epository
的倉庫地址,改成我們自定義的盤下面即可。
我的setting.xml是這樣的,如果還是看不懂的話,請移步Setting.xml相關配置

<mirrors>
	 <mirror>  
		<id>alimaven</id>  
		<name>aliyun maven</name>  
		<url>http://maven.aliyun.com/nexus/content/groups/public/</url>  
		<mirrorOf>central</mirrorOf>          
	</mirror>  
  </mirrors
複製程式碼

6.我們可以看到這個DemoApplication類, 這是整個Spring Boot應用的入口,有@SpringBootApplication這個註解,顯而易見。

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}
複製程式碼

7.接下來我們建立一個HelloController.java, @RestController這個註解的作用:宣告這是一個Controller類,返回json。其實就是@ResponseBody@Controller的結合體。

@RestController
public class HelloController {

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String say() {
        return "Hello, Spring Boot!";
    }
}
複製程式碼

8.啟動有3種方式。
(1)直接在Itellij IDEA啟動。

Paste_Image.png

(2)在專案的根目錄下,開啟命令視窗,輸入mvn spring-boot:run

Paste_Image.png

(3)在專案的根目錄下,開啟命令視窗,輸入mvn install,讓專案生成jar包。

Paste_Image.png

然後會發現target包下面多了一個jar包。

Paste_Image.png

輸入命令java -jar target/demo-0.0.1-SNAPSHOT.jar

Paste_Image.png

9.我們就可以訪問Spring Boot應用了。

Paste_Image.png

###專案屬性配置
1.我們可以在resources資料夾下面建3個propertiesapplication-dev.properties是開發環境下的配置檔案。application-prod.properties是應用環境下的配置檔案。Spring Boot預設讀取的配置檔案是application.properties,我們只需要在application.properties指定使用哪一個環境下的配置檔案即可。比如:spring.profiles.active=dev

Paste_Image.png

2.我們在application-dev.properties,配置一些資訊,讓我們的Controller類去讀取配置資訊。

server.port=8081
server.context-path=/girl
cupSize=A
height=160
content="cupSize: ${cupSize}, age: ${height}"
girl.cupSize=A
girl.height=160
複製程式碼

3.Controller類讀取配置資訊,啟動Spring Boot輸出結果。

public class HelloController {
    @Value("${cupSize}")
    private String cupSize;

    @Value("${height}")
    private String height;

    @Value("${content}")
    private String content;

    @RequestMapping(value = "/display", method = RequestMethod.GET)
    public String display() {
       return "cupSize=" + cupSize + ", height=" + height;
    }

    @RequestMapping(value = "/content", method = RequestMethod.GET)
    public String displayContent() {
        return content;
    }
}
複製程式碼
Paste_Image.png
Paste_Image.png

4.Controller類讀取配置資訊帶字首的字串,比如我們要讀取girl.cupSize=A girl.height=160 這些帶girl的配置資訊,我們該怎麼辦呢。我們需要定義一個GirlProperties.java@ConfigurationProperties代表我們要讀取帶什麼字首的配置資訊,@Component代表這個類已經在Spring配置檔案中註冊過。

@ConfigurationProperties(prefix = "girl")
@Component
public class GirlProperties {
    private String cupSize;
    private String height;

    public String getCupSize() {
        return cupSize;
    }

    public void setCupSize(String cupSize) {
        this.cupSize = cupSize;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }
}
複製程式碼

5.Controller類讀取GirlProperties,我們要使用@Autowired注入GirlProperties這個類的例項,它是通過bean的型別注入的。啟動Spring Boot應用,輸出結果。

@RestController
public class HelloController {
    @Autowired
    private GirlProperties girlProperties;

    @RequestMapping(value = "/properties", method = RequestMethod.GET)
    public String displayProperties() {
        return girlProperties.getCupSize() + girlProperties.getHeight();
    }
}
複製程式碼
Paste_Image.png

###Controller的使用
1.儘量使用@GetMapping@PostMapping 代替 @RequestMapping(value = "/xxxxx", method = RequestMethod.GET)
2.如果需要在Spring Boot使用@Controller,需要返回一個邏輯檢視。比如

@Controller
public class DemoController {
    @RequestMapping(value = "/saylove", method = RequestMethod.GET)
    public String sayLove() {
        return "index";
    }
}
複製程式碼

index.html是在templates資料夾下面的

Paste_Image.png

3.pom.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>girl</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
			<version>1.5.8.RELEASE</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>
複製程式碼

###資料庫操作
1.在application-dev.properties配置資料連線配置

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot
spring.datasource.username=root
spring.datasource.password=xiaoma96
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
複製程式碼

spring.jpa.hibernate.ddl-auto有4個屬性:
create: 不管資料庫原先有沒有這個表,每次啟動應用,都會drop這個表,然後再建立新的一張表。
update: 如果資料庫中有這個表且有資料,那麼我會保留這張表,不會去刪除它。
create-drop: 應用停止的時候, 會把資料庫裡面這張表刪除。
none: 不產生任何行為。

2.什麼是JPAJPA的英文全稱是Java Persistence API定義了一系列物件持久化的標準,目前實現這個規範的產品有Hibernate

3.怎麼去使用JPA? 之前用過Liferay技術, Liferay通過ServiceBuilder生成Service.xml,在這個Service.xml配置你需要建立資料庫表的entity資訊,然後定義一些方法的欄位。然後build一下。就會生成對應的CRUD方法,很是智慧。而且在下一次應用啟動時,會生成對應的資料庫表喲。如果需要定製化sql語句,只需要在finderImplServiceImpl裡面新增自己的方法,然後build一下,重新生成介面。同樣JPA,簡單的CRUD我們不需要去寫sql語句,只需要定義一個GirlRepository的介面,繼承JpaRepository<Girl, Integer>就行了。需要定製化CRUD,我們新增相應的方法就行了。

public interface GirlRepository extends JpaRepository<Girl, Integer> {

    public List<Girl> findByAge(Integer age);

    public List<Girl> findByCupSize(String cupSize);

    public List<Girl> findByName(String name);
}
複製程式碼

4.定義RESTfulAPI,開放CRUD介面。增加,使用POST, 查詢使用GET, 更新使用PUT,刪除使用DELETE

@RestController
public class GirlController {
    @Autowired
    private GirlRepository girlRepository;

    /**
     * Queries all girls.
     * @return girls List queryed
     */
    @GetMapping(value = "/girls")
    public List<Girl> girlList() {
        return girlRepository.findAll();
    }

    /**
     * Adds girl
     * @param name
     * @param cupSize
     * @param age
     * @return girl added
     */
    @PostMapping(value = "/girls")
    public Girl girlAdd(@RequestParam("name") String name, @RequestParam("cupsize") String cupSize
            , @RequestParam("age") Integer age) {
        Girl girl = new Girl();
        girl.setAge(age);
        girl.setName(name);
        girl.setCupSize(cupSize);
        return girlRepository.save(girl);
    }

    /**
     * Finds girl by id
     * @param id
     * @return girl finded
     */
    @GetMapping(value = "/girls/{id}")
    public Girl girlFindOne(@PathVariable("id") Integer id) {
        return girlRepository.findOne(id);
    }

    /**
     * Updates girl
     * @param id
     * @param name
     * @param cupSize
     * @param age
     * @return girl updated
     */
    @PutMapping(value = "/girls/{id}")
    public Girl girlUpdateOne(@PathVariable("id") Integer id, @RequestParam("name") String name, @RequestParam("cupsize") String cupSize
            , @RequestParam("age") Integer age) {
        Girl girl = new Girl();
        girl.setCupSize(cupSize);
        girl.setName(name);
        girl.setAge(age);
        girl.setId(id);
        return girlRepository.save(girl);
    }

    /**
     * Deletes girl by id
     * @param id
     */
    @DeleteMapping(value = "/girls/{id}")
    public void girlDeleteOne(@PathVariable("id") Integer id) {
        girlRepository.delete(id);
    }

    /**
     * Queries girls by name
     * @param name
     * @return girl list queryed
     */
    @GetMapping(value = "/girls/name/{name}")
    public List<Girl> girlFindByName(@PathVariable("name") String name) {
        return girlRepository.findByName(name);
    }

    /**
     * Queries girls by age
     * @param age
     * @return girl list queryed
     */
    @GetMapping(value = "/girls/age/{age}")
    public List<Girl> girlFindByAge(@PathVariable("age") Integer age) {
        return girlRepository.findByAge(age);
    }

    /**
     * Queries girls by cupsize
     * @param cupSize
     * @return girl list queryed
     */
    @GetMapping(value = "/girls/cupsize/{cupsize}")
    public List<Girl> girlFindByCupSize(@PathVariable("cupsize") String cupSize) {
        return girlRepository.findByCupSize(cupSize);
    }
}
複製程式碼

5.使用Postman軟體,測試API。在這裡,我就測試一個查詢api,演示一下。

Paste_Image.png

###事務管理
1.什麼是事務?事務是作為一個邏輯單元執行的一系列操作。它有4個特性

  • 原子性:事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要麼全部完成,要麼全部失敗。
  • 一致性: 一旦事務完成,不管成功還是失敗,系統必須確保它所建模的業務處於一致的狀態,而不全是部分完成,或者是部分失敗,在現實的資料不應有被破壞。
  • 隔離性: 可能有許多事務會同時處理相同的資料, 因此每個事務都應該與其他事務隔離開,防止資料被破壞。
  • 永續性: 一旦事務完成, 無論發生什麼,系統發生錯誤,它的結果都不應該受到影響,這樣就能從任何系統崩潰中恢復過來, 通常情況下,事務的記過被寫到持久化儲存器。

2.我們常用的幾個事務:

  • PROPAGATION_REQUIRED: 如果存在一個事務,則支援當前的事務,如果沒有則開啟。
  • PROPAGATION_SUPPORTS: 如果存在一個事務,就支援當前事務, 如果沒有事務,則以非事務執行。
  • PROPAGATION_REQUIRES_NEW: 啟動一個新的事務,不依賴當前事務,當前事務掛起。

3.我們模擬一個事務的回滾,體現事務的原子性,第一個save操作不會出現問題,第二個save操作會丟擲異常。但是不能部分成功,不能部分失敗。這二個操作最終會被回滾。

@Service
public class GirlService {

    @Autowired
    private GirlRepository girlRepository;

    @Transactional
    public void insertTwo() {
        Girl girlA = new Girl("garrett-test", 18, "Z");
        girlRepository.save(girlA);

        Girl girlB = new Girl("mayday-test", 21, "BBBBBBBB");
        girlRepository.save(girlB);
    }
}

@RestController
public class GirlController {
    @Autowired
    private GirlService girlService;

    /**
     * Tests transaction
     */
    @GetMapping(value = "/transaction")
    public void transactionTest() {
        girlService.insertTwo();
    }
}
複製程式碼

4.啟動應用,開啟Postman,測試API。很顯然,操作發生異常進行回滾,資料庫未插入任何資料。

image.png

####尾言
學無止境,一起共勉。

相關文章