一、SpringBoot簡介
1.什麼是SpringBoot
產生背景:Spring開發比較繁瑣,配置檔案很多,部署流程複雜,整合第三方框架難度大。這會降低開發效率
SpringBoot是一個簡化Spring應用建立和開發的框架
整合了整個Spring技術棧,是JavaEE開發一站式解決方案
2.為什麼使用SpringBoot
優點:
- 可以快速構架Spring專案,並與主流框架進行整合
- 內建Servlet容器,不需要手動部署war包
- 使用starter管理依賴並進行版本控制
- 大量自動配置,簡化開發
- 提供準生產環境的執行時監控
- 不需要XML檔案
二、第一個SpringBoot程式
1.操作步驟
步驟:
1.1 建立一個Maven的jar工程
傳統的應用需要建立web工程,然後將應用打成war包,然後部署在容器中
而SpringBoot只需要打成一個jar包,其中內建了tomcat
1.2 匯入SpringBoot相關依賴
<?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>com.ly</groupId>
<artifactId>springboot01-helloworld</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
</parent>
<name>springboot01-helloworld</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
</build>
</project>
複製程式碼
1.3 建立Controller
package com.ly.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Author: LuYi
* Date: 2019/10/27 11:05
* Description: 描述
*/
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "Hello World";
}
}
複製程式碼
1.4 建立啟動類
package com.ly;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Author: LuYi
* Date: 2019/10/27 11:05
* Description: 使用@SpringBootApplication將類標註成SpringBoot應用
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
複製程式碼
預設會掃描@SpringBootApplication
註解所在的包及其子包,也可使用@ComponentScan("com.ly.controller")
註解進行指定
1.5 打包
<!--該外掛可以將應用打包成一個可執行的jar包-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
複製程式碼
新增該外掛,將應用打成可執行的jar包, 執行:java -jar jar檔案
2. 分析HelloWorld
2.1 POM檔案
-
父工程
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> </parent> 複製程式碼
-
父工程的父工程:用來管理SpringBoot應用中依賴的版本,進行版本控制
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.9.RELEASE</version> <relativePath>../../spring-boot-dependencies</relativePath> </parent> 複製程式碼
-
依賴:通過
starter
指定依賴<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 複製程式碼
SpringBoot提供了很多starter(啟動器),分別對應了不同的應用場景,當在專案中引入這些starter時,相應場景的依賴就會被匯入進來
2.2 啟動類
@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}
)}
)
複製程式碼
-
@SpringBootApplication
標註在類上,表示這個類是SpringBoot的啟動類,通過該類的Main方法啟動SpringBoot應用
-
@SpringBootConfiguration
標註在類上,表示這個類是SpringBoot的配置類
層級關係:SpringBootConfiguration——>@Configuration——>@Component
@Configuration:標註在類上,表示這個類是Spring的配置類,相當於XML配置檔案
-
@EnableAutoConfiguration
開啟自動配置功能,簡化了以前繁瑣的配置
SpringBoot在啟動時會在/META-INF/spring.factories中EnableAutoConfiguration指定的值,將這些值作為自動配置類新增到容器中,這些自動配置類會幫我們完成很多配置工作。
-
@ComponentScan
標註在類上,指定要掃描的包及其子包
三、快速建立SpringBoot專案
1.簡介
使用Spring initializer快速構建SpringBoot專案
2. 基本操作
-
pom檔案和主程式類自動生成,直接寫業務邏輯即可
-
resources資料夾的目錄結構
|-static 存放靜態資源,如js,css,images |-template 存放模板引擎,如freemarker、thymeleaf等 |-application.properties SpringBoot應用的配置檔案,可以修改預設設定 複製程式碼
四、配置檔案
1.簡介
SpringBoot的預設全域性配置檔案有兩種:
- application.properties
- application.yml
檔名固定,存放在classpath:/或classpath:/config/目錄下
可以修改Spring Boot預設配置,具體參考: docs.spring.io/spring-boot…
注意:SpringBoot2.0和1.0的配置有區別,有的配置項已被刪除
2.YAML用法
2.1 簡介
YAML不是一種標記語言,YAML是專門用來寫配置檔案的,它以資料為中心,簡介強大,比xml和properties更適合做配置檔案
YAML檔案以.yml或.yaml為後置名
2.2 application.yml
server:
port: 8081 #寫法:key: value 冒號後面必須有空格
servlet:
context-path: /springboot03/
複製程式碼
2.3 語法規則
- 大小寫敏感
- 使用縮排表示層級關係
- 縮排時不允許使用Tab鍵
- 縮排的空格數目不重要,但是要與對應的層級的左側對齊
#
表示註釋
2.4 基本用法
YAML支援的資料結構有三種:
- 字面量:單個的,不可再分的值(字串、數字、boolean值)
- 物件:鍵值對集合
- 陣列:一組按次序排列的值
三種資料結構的用法:
1.字面量:普通的值,如數字、字串、布林值
number: 12.5
str: hello
name: 'tom cruise' #如字串包含空格及特殊字元需要使用 引號 引起來
name: 'tom \n cruise' #不會對特殊字元進行轉義 結果為:tom 換行 cruise
name: "tom \n cruise" #對特殊字元進行轉義,會作為普通字元輸出, 結果為 tom \n cruise
複製程式碼
-
物件,也成為對映Map,包含屬性和值
# 寫法1:換行寫 user: name: tom age: 20 sex: male # 寫法2:行內寫法 user: {name: tom, age: 20, sex: male} 複製程式碼
- 陣列,如List、Set等
# 寫法1: 一組短橫線開頭的行 names: - tom - jack - alice # 寫法2: 行內寫法 name: {tom,jack,alice} 複製程式碼
3. 為屬性注入值
通過載入配置檔案,為類中的屬性注入值
3.1 編寫application.yml
user:
username: admin
age: 21
status: true
birthday: 2019/2/14
address:
province: 黑龍江省
city: 哈爾濱市
lists:
- list1
- list2
- list3
maps: {k1: v1,k2: v2}
複製程式碼
3.2 建立實體類
User
package com.luyi.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Author: LuYi
* Date: 2019/10/27 13:49
* Description: 通過載入配置檔案為當前類中的屬性注入值
*/
// 必須將當前類加入到容器
@Component
// 預設讀取全域性配置檔案獲取值,當前類中的所有屬性與 user 進行繫結
@ConfigurationProperties(value = "user")
public class User {
private String username;
private Integer age;
private Boolean status;
private Date birthday;
private Address address;
private List<String> lists;
private Map<String, Object> maps;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public List<String> getLists() {
return lists;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", age=" + age +
", status=" + status +
", birthday=" + birthday +
", address=" + address +
", lists=" + lists +
", maps=" + maps +
'}';
}
}
複製程式碼
Address
package com.luyi.bean;
/**
* Author: LuYi
* Date: 2019/10/27 13:50
* Description: 描述
*/
public class Address {
private String province;
private String city;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
複製程式碼
3.3 測試
package com.luyi.springboot03config;
import com.luyi.bean.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Springboot03ConfigApplicationTests {
@Autowired
private User user;
@Test
void contextLoads() {
System.out.println(user);
}
}
複製程式碼
3.4 新增配置檔案處理器依賴(可選)
<!--配置檔案處理器,自動生成後設資料資訊,編寫配置檔案會有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
複製程式碼
3.5 使用properties配置檔案
user.username=alice
user.age=22
user.status=false
user.birthday=2019/10/27
user.address.province=黑龍江省
user.address.city=哈爾濱
user.lists=list1,list2,list3
user.maps.k1=v1
user.maps.k2=v2
複製程式碼
注意:在IDEA中預設使用UTF-8編碼,properties檔案預設使用ASCII編碼,所以會出現亂碼,可通過勾選解決
優先順序:properties > yml
3.6 使用@Value註解注入值
@Value("${user.username}")
private String username;
@Value("${user.age}")
private Integer age;
@Value("${user.status}")
private Boolean status;
@Value("${user.birthday}")
private Date birthday;
//@Value不支援複雜型別封裝
private Address address;
@Value("${user.lists}")
private List<String> lists;
private Map<String, Object> maps;
複製程式碼
@Value與@ConfigurationProperties比較:
- 前者只可以單值注入,後者可以批量注入
- 前者不支援為複雜型別封裝,後者支援
4.多環境配置
可以為不同環境提供不同配置資訊,如開發環境、測試環境、生產環境等
兩種方式:
- 建立多個properties檔案
- 定義yml文件塊
4.1 建立多個properties檔案
步驟:
1.建立不同環境的properties檔案
檔案命名必須符合aplication-xxx.properties的格式
application-dev.properties
server.port=9991
複製程式碼
application-test.properties
server.port=9992
複製程式碼
application-prod.properties
server.port=9993
複製程式碼
2.在application.properties中指定需要啟用的配置
#指定要啟用的配置
spring.profiles.active=prod
複製程式碼
4.2 定義yml文件塊
1.在yml中使用三個短橫線定義多個文件塊
spring:
profiles: dev
server:
port: 9991
---
spring:
profiles: test
server:
port: 9992
---
spring:
profiles: prod
server:
port: 9993
複製程式碼
2.在第一個文件塊指定要啟用的環境
spring:
profiles:
active: test
---
複製程式碼
5.載入外部配置檔案
5.1 載入properties屬性檔案
問題:@ConfigurationProperties預設是從全域性配置檔案中讀取值,如果想自定義屬性檔案中獲取值怎麼辦?
解決:使用@PropertySource註解載入外部屬性檔案
// 必須將當前類加入到容器
@Component
//載入外部的屬性檔案
@PropertySource({"classpath:user.properties"})
// 預設讀取全域性配置檔案獲取值,當前類中的所有屬性與 user 進行繫結
@ConfigurationProperties(value = "user")
public class User{
複製程式碼
5.2 載入spring配置檔案
問題:如果有資訊需要寫道xml檔案中,想載入xml檔案怎麼辦
解決:使用@ImportResource載入外部配置檔案
5.3 使用註解方式新增元件
推薦使用全註解方式向Spring容器新增元件,@Configuration和@Bean
/**
* Author: LuYi
* Date: 2019/10/28 14:49
* Description: 描述
*/
//新增在類上,表示這個類是一個配置類,相當於spring配置檔案
@Configuration
public class SpringConfig {
//標註在方法上,用來向容器中新增元件,將方法的返回值新增到容器中,方法名作為bean的id
@Bean
public Address address(){
Address address = new Address();
address.setProvince("山東");
address.setCity("日照");
return address;
}
}
複製程式碼
五、SpringBoot自動配置原理
1.執行流程
1.SpringBoot啟動時載入主配置類,使用@EnableAutoConfiguration開啟了自動配置功能
2.@EnableAutoConfiguration中使用了 @Import({AutoConfigurationImportSelector.class})向容器中新增了一些元件(自動配置類)
檢視AutoConfigurationImportSelector類中的selectImports方法,再點選getAutoConfigurationEntry方法中的`getCandidateConfigurations方法
通過getCandidateConfigurations中的loadFactoryNames方法載入到SpringFactory,
再通過classLoader載入META-INF/spring.factories
的配置,從配置中獲取EnableAutoConfiguration(spring-boot-autoconfigure-2.1.9.RELEASE.jar)對應的值。
將這些自動配置類(xxxAutoConfiguration)新增到容器中
3.通過自動配置類完成自動配置功能。
2. 原理分析
以HttpEncodingAutoConfiguration為例,就是以前在web.xml中配置的CharacterEncodingFilter過濾器
//表示這是一個配置類,相當於以前編寫的Spring配置檔案
@Configuration
//啟用HttpProperties類的ConfigurationProperties功能,通過配置檔案為屬性注入值,並將其新增到容器中
@EnableConfigurationProperties({HttpProperties.class})
//當該應用是web應用時才生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//必須包含CharacterEncodingFilter類才生效
@ConditionalOnClass({CharacterEncodingFilter.class})
//如果配置檔案中有spring.http.encoding選項則該配置生效,否則不生效。但是預設已經生效了
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
//將容器中的HttpProperties注入
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
//將返回的filter新增到容器中,作為bean
@Bean
//如果容器中沒有這個bean才會生效
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
複製程式碼
//從配置檔案中獲取指定的值,然後繫結到指定的屬性值
@ConfigurationProperties(
prefix = "spring.http"
)
public class HttpProperties {
private Charset charset;
private Boolean force;
private Boolean forceRequest;
private Boolean forceResponse;
private Map<Locale, Charset> mapping;
複製程式碼
注意:
- 根據當前情況進行判斷,決定配置類是否生產,如果不滿足條件自動配置就不會生效
- 自動配置類xxAutoConfiguration的屬性是從對應的xxProperties類中獲取
- xxProperties類中的資訊是通過配置檔案注入繫結的,可以通過配置檔案指定屬性的值
3.總結
- SpringBoot在啟動時會載入大量的自動配置類
- 通過自動配置了向容器中新增元件
- 通過這些元件自動完成許多功能,從而簡化配置
可以通過開啟debug模式檢視自動配置類的匹配情況
#開啟debug模式
debug=true
複製程式碼
六、Web開發
1.簡介
使用SpringBoot開發Web應用的步驟:
1.建立SpringBoot專案,新增對應的starter
2.在配置檔案中指定必要的少量配置
3.編寫業務程式碼
Web開發的自動配置類WebMvcAutoConfiguration
2.關於靜態資源的對映
2.1 靜態資源的位置
檢視WebMvcAutoConfiguration——>addResourceHandlers()——>getStaticLocations()——>staticLocations
靜態資源的預設位置
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
複製程式碼
可以通過上面的資料夾可以訪問到靜態資源
也可以在配置檔案中自己指定可以訪問的位置
# 指定靜態資源的位置 存放在根目錄下的public資料夾中
spring.resources.static-locations=classpath:/public
複製程式碼
2.2 歡迎頁
檢視WebMvcAutoConfiguration—>welcomePageHandlerMapping()—>getWelcomePage()
將index.html頁面放到任意一個靜態資原始檔夾中的
2.3 網站圖示
檢視WebMvcAutoConfiguration—>內部類FaviconConfiguration—>faviconHandlerMapping
將favicon.ico放到靜態資源的任意資料夾中即可
七、模板引擎
1.簡介
目前Java Web開發推薦使用模板引擎,不建議使用jsp頁面
- jsp的缺點:本質時Servlet,需要後臺進行編譯,效率較低
- 模板引擎:不需要編譯,速度快
常用的模板引擎:Freemarker、Thymeleaf等
SpringBoot推薦Thymeleaf,且預設不支援jsp,因為jsp必須要打成war包。
補充:目前主流的web開發更推薦前後端分離,前端使用MVVM框架,Vue.js、Angular、React等
2.Thymeleaf的使用
步驟:
1.新增Thymeleaf的依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
複製程式碼
2.將html頁面放到templates下
templates下的html不能直接訪問,需要使用Controller跳轉,由Thymeleaf進行渲染
ThymeleafAutoConfiguration—>ThymeleafProperties
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
複製程式碼
預設拼接字首和字尾
3.使用thymeleaf
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>success</h2>
<!--使用th:text屬性設定元素中的文字,表示式:${}可以獲取作用域中的資料-->
<p th:text="${name}"></p>
</body>
</html>
複製程式碼
4.修改頁面後,讓其實時生效
由於thymeleaf預設啟用了快取,將快取禁用掉
#禁用thymeleaf的快取
spring.thymeleaf.cache=false
複製程式碼
補充:還需要開啟idea的自動編譯,idea預設儲存時不會自動編譯
3.語法規則
3.1 常用屬性
-
th:text、th:utext
設定元素中的文字內容
th:text對特殊字元進行轉義,等價於內聯方式[[${ }]]
th:utext不對特殊字符集進行轉義,等價於內聯方式[(${ })]
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--th:text、th:utext--> <div th:text="${hello}">aaa</div> <div th:utext="${hello}">bbb</div> <!--使用內聯方式,可以在文字前後新增內容--> <div>[[${hello}]]aaa</div> <div>[(${hello})]bbb</div> </body> </html> 複製程式碼
-
th:html原生屬性
用來替換指定的html原生屬性的值
@RequestMapping("/test2") public String test2(Model model){ model.addAttribute("hello", "<mark>你好</mark>"); model.addAttribute("id", "mydiv"); model.addAttribute("title", "this is a div"); return "result"; } 複製程式碼
<!--th:html原生屬性--> <div id="div1" title="這是一個div" th:id="${id}" th:title="${title}">div</div> 複製程式碼
-
th:if、th:unless、th:switch、th:case
條件判斷,類似於if
<!--th:if、th:unless、th:switch、th:case--> <div th:if="${age>=18}">成年</div> <p th:unless="${age<18}">成年</p> <p th:switch="${role}"> <span th:case="student">學生</span> <span th:case="teacher">老師</span> <span th:case="*">其他</span> </p> <hr> 複製程式碼
-
th:each
迴圈,類似於for each
<!--th:each--> <ul> <li th:each="name:${names}" th:text="${name}"></li> </ul> 複製程式碼
-
th:object、th:field
用於表單資料物件的繫結,將表單繫結到Controller的一個JavaBean引數,常與th:field
一起使用,需要和*{}選擇表示式配合使用
<!--th:object、th:field--> <h2>修改使用者資訊</h2> <!--th:object指定物件,th:field指定屬性--> <form action="modify" method="post" th:object="${user}"> 編號:<input type="text" th:field="*{id}" readonly> <br> 姓名:<input type="text" th:field="*{name}"> <br> 年齡:<input type="text" th:field="*{age}"> <br> <input type="submit" value="修改"> </form> 複製程式碼
-
th:fragment
宣告程式碼片段,常用於頁面頭部和尾部的引入
<!--th:fragment--> <header th:fragment="head"> 這是頁面的頭部,導航 </header> 複製程式碼
-
th:include、th:insert、th:replace
引入程式碼片段,類似於jsp:include
<!--th:include、th:insert、th:replace--> <!--引入templates/include下的header.html頁面中的fragment為head的片段--> <div th:include="include/header::head"></div> 複製程式碼
三者之間的區別
th:include會保留自己的標籤,不要th:fragment的標籤(Thymeleaf 3.0 後不推薦使用)
th:insert保留自己的標籤,也保留th:fragment的標籤
th:relpace不保留自己的標籤,保留thfragment的標籤
3.2 表示式
-
${} 變數表示式
獲取物件的屬性、方法
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--獲取物件的屬性、方法--> <div th:text="${user.name}"></div> <div th:text="${user['age']}"></div> <div th:text="${users[1].name}"></div> <!--<div th:text="${users.size()}"></div>--> <div>[[${users.size()}]]個</div> </body> </html> 複製程式碼
使用內建的基本物件,如session和application
<!--使用內建基本物件--> <div th:text="${session.sex}"></div> <div th:text="${application.hobby}"></div> 複製程式碼
使用內建的工具物件,如#strings、#dates、#arrays、#lists、#maps等
<!--使用內建的工具物件--> <div th:text="${#strings.startsWith(user.name, 't')}"></div> <div th:text="${#strings.substring(user.name, 0, 2)}"></div> <div th:text="${#strings.length(user.name)}"></div> <div th:text="${#dates.createNow()}"></div> <div th:text="${#dates.create(2018, 10, 14)}"></div> <div th:text="${#dates.format(birthday, 'yyyy-MM-dd HH:mm:ss')}"></div> 複製程式碼
-
*{} 選擇表示式(星號表示式)
<!--*{}選擇表示式--> <div th:object="${user}"> <div th:text="*{id}"></div> <div th:text="*{name}"></div> <div th:text="*{age}"></div> </div> 複製程式碼
-
@{} url表示式
<head> <meta charset="UTF-8"> <title>Title</title> <!--url表示式引入css檔案--> <link rel="stylesheet" th:href="@{/css/style.css}"> </head> <!--url表示式--> <a th:href="@{/findUser(name=${user.name})}">查詢指定的使用者資訊</a> <a href="product/list.html" th:href="@{/product/list}">商品列表</a> <script th:src="@{/js/common.js}"></script> 複製程式碼
-
運算子
eq gt le == != 三目運算子
4.熱部署
使用SpringBoot提供的devtools實現熱部署
原理:實時監控classpath下檔案的變化,如果發生變化自動重啟
配置:新增devtools依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!--該依賴不傳遞-->
<optional>true</optional>
</dependency>
複製程式碼
八、擴充套件預設的SpringMVC功能
1.簡介
以前在SpringMVC中可以通過如下程式碼進行檢視跳轉和攔截器:
<mvc:view-controller path="/showLogin" view-name="login"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.luyi.interceptor.HelloInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
複製程式碼
SpringBoot預設配置預設沒有提供以上功能,需要自己擴充套件,使用WebMvcConfigurer介面
2.基本操作
步驟:
1.定義一個配置類,實現WebMvcConfigurer介面
2.實現需要的方法
/**
* Author: LuYi
* Date: 2019/10/29 17:58
* Description: 擴充套件預設的SpringMVC的功能
* 要求:
* 1.將該類標記為配置類
* 2.實現WebMvcConfigurer介面
* 3.根據需要實現介面中相應的方法
*
* 注意:這個介面中的方法都新增了jdk1.8中的default方法修飾,不強制實現所有方法(jdk1.8新特性)
* 在SpringBoot1.0中是繼承WebMvcConfigurerAdapter類,SpringBoot2.0是基於jdk1.8的,
* 所以通過實現WebMvcConfigurer的方式
*/
//將該類設定為配置類
@Configuration
public class CustomMvcConfig implements WebMvcConfigurer {
//新增ViewController
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//將訪問login頁面的url設定為showLogin
registry.addViewController("/showLogin").setViewName("login");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/test2");
}
}
複製程式碼
九、全域性異常處理
1.簡介
當程式出現異常時進行全域性處理,SpringBoot預設的異常資訊提示:Whitelabel Error Page
兩種方式:
- 定義錯誤碼頁面
- 定義異常通知
2.定義錯誤碼頁面
建立 錯誤狀態碼.html
頁面,放到templates/error目錄中,當發生錯誤時會自動到該目錄下查詢對應的錯誤頁面
可以建立如 4xx.html
或5xx.html
頁面,用來匹配所有該型別的錯誤(會優先進行精確匹配
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>5xx錯誤</h2>
<h3>狀態碼:[[${status}]]</h3>
<h3>異常訊息:[[${message}]]</h3>
<h3>錯誤提示:[[${error}]]</h3>
<h3>時間戳:[[${timestamp}]]</h3>
</body>
</html>
複製程式碼
3.定義異常通知
/**
* Author: LuYi
* Date: 2019/10/29 18:45
* Description: 異常通知:用來處理全域性異常
*/
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(ArithmeticException.class)
public String arithmetic(Exception e){
System.out.println("警報:程式出現異常,發簡訊:" + e.getMessage());
return "error/5xx";
}
@ExceptionHandler(Exception.class)
public String exception(Exception e){
System.out.println("警報:程式出現異常,發郵件:" + e.getMessage());
return "error/5xx";
}
}
複製程式碼
十、關於Servlet容器
1.簡介
SpringBoot中預設內建了Servlet:Tomcat
問題:SpringBoot預設以jar包方式啟動內建的Servlet容器,沒有web.xml檔案,如何註冊Servlet三大元件:Servlet、Filter、Listener
解決:通過自定義Servlet配置,使用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean
2.註冊Servlet元件
步驟:
1.定義一個配置類
2.自定義一個方法,用來註冊元件
/**
* Author: LuYi
* Date: 2019/10/29 19:12
* Description: 自定義Servlet配置
*/
//將該類宣告為配置類
@Configuration
public class CustomServletConfig {
//將方法返回值放到Spring容器
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean<>();
//對MyServlet進行註冊
registrationBean.setServlet(new MyServlet());
ArrayList<String> urls = new ArrayList<>();
urls.add("/myServlet");
registrationBean.setUrlMappings(urls);
return registrationBean;
}
//註冊Filter
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
//註冊filter
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/showLogin", "/test1");
return registrationBean;
}
//註冊Listener
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>();
registrationBean.setListener(new MyListener());
return registrationBean;
}
}
複製程式碼
3.使用外部的Servlet容器
3.1 優缺點
使用內建Servlet容器:
優點:使用簡單,將應用打成jar包
缺點:不支援jsp、可定製性不高
使用外部的Servlet容器
優點:支援jsp、可定製性高
缺點:需要將應用打成war包
3.2 操作步驟
步驟:
1.建立一個Maven的war工程
有如下三個變化
1.打包方式變為war
<packaging>war</packaging>
複製程式碼
2.將內建的tomcat的scope配置為provided
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
複製程式碼
3.定義了一個SpringBootServletInitializer的子類
/**
* 要求:
* 1.必須繼承SpringBootServletInitializer
* 2.重寫configure()方法
* 3.呼叫SpringApplicationBuilder的sources()方法,傳入主程式類的
*/
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Springboot05WarApplication.class);
}
}
複製程式碼
2.建立web目錄的結構
3.配置字首和字尾
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
複製程式碼
4.配置Tomcat
要使用SpringBoot需要的Tomcat版本
十一、SpringBoot資料訪問
1.JDBC
步驟:
1.建立工程,選擇以下模板:web、jdbc、mysql
2.配置資料庫連線資訊
#指定資料庫連線引數
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
#指定資料來源
spring.datasource.type=org.apache.commons.dbcp.BasicDataSource
複製程式碼
3.測試
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class Springboot06JdbcApplicationTests {
@Autowired
private DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println("---------------------------");
System.out.println("DataSource的型別: " + dataSource.getClass());
System.out.println("Connection的連線: " + dataSource.getConnection());
}
}
複製程式碼
4.配置連線池引數
spring.datasource.initialSize=10
spring.datasource.maxActive=100
spring.datasource.minIdle=5
spring.datasource.maxWait=50000
複製程式碼
問題:新增上面的引數不生效,因為SpringBoot預設並不支援這些引數(DataSourceProperties)
解決:自定義資料來源配置
/**
* Author: LuYi
* Date: 2019/10/30 16:09
* Description: 描述
*/
@Configuration
public class DatasourceConfig {
@Bean
//從配置檔案中讀取spring.datasource屬性,並注入給資料來源的屬性
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource(){
return new BasicDataSource();
}
}
複製程式碼
5.使用JdbcTemplate運算元據庫
/**
* Author: LuYi
* Date: 2019/10/30 16:17
* Description: 描述
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private JdbcTemplate jdbcTemplate;
@RequestMapping("/findAll")
@ResponseBody
public List<Map<String, Object>> findAll(){
String sql = "select * from t_user";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
return list;
}
}
複製程式碼
2.MyBatis
2.1 基本步驟
1.建立工程,先擇以下模組:web、mybatis
2.配置資料來源
#配置DataSource
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
initialSize: 5
maxActive: 100
minIdle: 3
maxWait: 50000
#配置MyBatis
mybatis:
type-aliases-package: com.luyi.pojo
mapper-locations: classpath:mapper/*.xml
複製程式碼
3.編寫Mapper、Service、Controller
4.配置MyBatisConfig配置類
/**
* Author: LuYi
* Date: 2019/10/30 16:57
* Description: 描述
*/
@Configuration
//掃描MyBatis介面所在的包
@MapperScan("com.luyi.mapper")
public class MyBatisConfig {
@Bean
//載入主配置檔案,注入配置資訊
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource(){
return new DruidDataSource();
}
}
複製程式碼
2.2 配置PageHelper分頁外掛
步驟:
1.新增PageHelper依賴
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
複製程式碼
2.配置PageHelper的屬性
#配置PageHelper
pagehelper:
helper-dialect: mysql
複製程式碼
3.使用PageHelper
@Override
public PageInfo<User> findByPage(int pageNum, int pageSize) {
//使用PageHelper設定分頁
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
return pageInfo;
}
複製程式碼
2.3 使用MyBatis Plus
參考:mp.baomidou.com/
步驟:
1.新增MyBatis Plus的依賴
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
複製程式碼
2.配置全域性配置檔案
#配置DataSource
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
initialSize: 5
maxActive: 100
minIdle: 3
maxWait: 50000
#配置MyBatis Plus
mybatis-plus:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.luyi.pojo
global-config:
db-config:
#主鍵型別
id-type: auto
#欄位策略
field-strategy: not_empty
#駝峰下劃線轉換
table-underline: true
#全域性表字首
table-prefix: t_
#重新整理mapper神器
refresh-mapper: true
複製程式碼
3 配置MyBatis Plus
/**
* Author: LuYi
* Date: 2019/10/31 9:59
* Description: 描述
*/
@Configuration
@MapperScan("com.luyi.mapper")
public class MyBatisPlusConfig {
/**
* 分頁外掛,自動識別資料庫型別
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource(){
return new DruidDataSource();
}
}
複製程式碼
4.編寫Mapper,繼承BaseMapper
/**
* Author: LuYi
* Date: 2019/10/31 10:07
* Description: 繼承BaseMapper介面
*/
public interface UserMapper extends BaseMapper<User> {
}
複製程式碼
5.測試
@RunWith(SpringRunner.class)
@SpringBootTest
class Springboot08MpApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
}
@Test
public void add(){
User user = new User();
user.setUsername("xxx");
user.setPassword("111");
userMapper.insert(user);
System.out.println("-------------" + user);
}
@Test
public void removeById(){
int i = userMapper.deleteById(3);
System.out.println(i);
}
@Test
public void modifyById(){
User user = new User();
user.setId(6);
user.setUsername("zhangsan");
user.setPassword("123");
userMapper.updateById(user);
}
@Test
public void findById(){
User user = userMapper.selectById(1);
System.out.println(user);
}
@Test
public void findByCondition(){
//定義條件構造器,用來封裝查詢條件
QueryWrapper<User> wrapper = new QueryWrapper<>();
// wrapper.eq("username", "tom");
wrapper.like("username", "%a%");
List<User> users = userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void findByPage(){
Page<User> page = new Page<>(2, 2);
QueryWrapper<User> wrapper = new QueryWrapper<>();
IPage<User> userIPage = userMapper.selectPage(page, wrapper.select("id", "username", "password"));
assertThat(page).isSameAs(userIPage);
System.out.println("總條數---->" + userIPage.getTotal());
System.out.println("當前頁數---->" + userIPage.getCurrent());
System.out.println("當前每頁顯示數---->" + userIPage.getSize());
System.out.println(userIPage.getRecords());
System.out.println("----------自帶分頁----------");
}
}
複製程式碼
補充:lombok的使用
步驟:
1.新增依賴
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
複製程式碼
2.使用lombok提供的註解
/**
* Author: LuYi
* Date: 2019/10/30 16:32
* Description: Lombok的使用
* Lombok提供了許多註解,標註在類上或者屬性上
*/
@Getter
@Setter
@ToString
@Data //相當於以上註解
@TableName(value = "t_user") //指定當前資料庫表的名稱
public class User implements Serializable {
private Integer id;
private String username;
private String password;
}
複製程式碼
3.在Idea中安裝lombok外掛
由於原始碼中沒有getter/setter等的定義,Idea無法識別,可以安裝lombok外掛解決
十二、SpringBoot整合Redis
1.簡介
Redis是一個記憶體資料庫,可以作為快取、訊息中介軟體、key-value資料庫等來使用
2.操作
步驟:
1.新增依賴
注意:在SpringBoot1.0中使用的Redis客戶端時Jedis,在SpringBoot2.0中使用的時Lettuce
<!--整合Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--SpringBoot2.0使用的Redis客戶端時Lettuce-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
複製程式碼
2.配置redis
#redis配置
spring.redis.host=192.168.52.128
spring.redis.port=6379
spring.redis.database=0
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=3
複製程式碼
3.基本用法
使用SpringDataRedis提供的工具類:StringRedisTemplate、RedisTemplate
封裝JsonUtils
/**
* Author: LuYi
* Date: 2019/10/31 17:37
* Description: Json工具類,基於jackson
*/
public class JsonUtils {
//獲取jackson物件
private static ObjectMapper objectMapper = new ObjectMapper();
/**
* 將物件轉換為Json字串
*/
public static String objectToJson(Object obj){
try {
//將物件轉換為Json字串
String jsonStr = objectMapper.writeValueAsString(obj);
return jsonStr;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 將Json字串轉換為物件
*/
public static <T> T jsonToObject(String jsonStr, Class<T> clazz){
try {
T t = objectMapper.readValue(jsonStr, clazz);
return t;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
複製程式碼
測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot09RedisApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Test
public void contextLoads() {
}
/**
* 使用StringRedisTemplate
* Redis資料型別:String、List、Set、ZSet、Hash
*/
@Test
public void test1(){
/**
* 操作redis
*/
// ValueOperations<String, String> value = stringRedisTemplate.opsForValue();
// ListOperations<String, String> list = stringRedisTemplate.opsForList();
// SetOperations<String, String> set = stringRedisTemplate.opsForSet();
// ZSetOperations<String, String> zset = stringRedisTemplate.opsForZSet();
// HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
/**
* 操作String
*/
// stringRedisTemplate.opsForValue().set("username", "admin");
// System.out.println(stringRedisTemplate.opsForValue().get("username"));
/**
* 操作List
*/
// stringRedisTemplate.opsForList().leftPush("name", "tom");
// stringRedisTemplate.opsForList().leftPushAll("name", "aaa", "bbb", "ccc");
// System.out.println(stringRedisTemplate.opsForList().range("name", 0, -1));
/**
* 儲存物件
*/
User user = new User();
user.setId(1001);
user.setUsername("tom");
user.setPassword("123");
//將物件轉換為json格式
String jsonStr = JsonUtils.objectToJson(user);
System.out.println(jsonStr);
stringRedisTemplate.opsForValue().set("user", jsonStr);
//獲取jsonStr
String str = stringRedisTemplate.opsForValue().get("user");
//將str轉換為物件
User u = JsonUtils.jsonToObject(str, User.class);
System.out.println(u);
}
/**
* 使用redisTemplate
*/
@Test
public void test2(){
redisTemplate.opsForValue().set("sex", "male");
String sex = redisTemplate.opsForValue().get("sex");
System.out.println(sex);
}
}
複製程式碼