目錄
1. 第一個(gè)SpringBoot項(xiàng)目(HelloWorld)
2. starter機(jī)制
3. YAML標(biāo)記語(yǔ)言
4. 配置文件
5. 日志(記錄運(yùn)行情況在讶、定位問(wèn)題)
6. 靜態(tài)資源映射
7. Thymeleaf模板引擎
8. 國(guó)際化
一款用于簡(jiǎn)化Spring項(xiàng)目搭建和開(kāi)發(fā)的開(kāi)源框架(使開(kāi)發(fā)者更專注于業(yè)務(wù)邏輯)煞抬。
SpringBoot的特點(diǎn)
1. 以Spring為基礎(chǔ),使用更簡(jiǎn)單构哺、功能更豐富革答、性能更穩(wěn)定健壯。
2. 提供了大量開(kāi)箱即用的依賴包(starter機(jī)制):自動(dòng)管理依賴包中的依賴(簡(jiǎn)化了復(fù)雜的依賴包管理);提供了大量默認(rèn)/自動(dòng)配置(省去了大量的XML配置內(nèi)容)蝗碎,不需要任何形式的配置即可實(shí)現(xiàn)Spring的所有配置(可以通過(guò)配置文件修改默認(rèn)配置)湖笨。
3. 內(nèi)嵌了Servlet容器(如:Tomcat、Jetty蹦骑、Undertow等)慈省,應(yīng)用無(wú)需打成WAR包 。
4. 可在終端執(zhí)行java–jar xxx.jar命令來(lái)獨(dú)立運(yùn)行SpringBoot項(xiàng)目眠菇。
5. 可對(duì)正在運(yùn)行的項(xiàng)目提供監(jiān)控边败。
隨著微服務(wù)技術(shù)的流行,SpringBoot也成了時(shí)下炙手可熱的技術(shù)捎废。
1. 第一個(gè)SpringBoot項(xiàng)目(HelloWorld)
===》1. 創(chuàng)建項(xiàng)目
方式1(創(chuàng)建Maven項(xiàng)目)
1. 修改pom.xml文件(添加SpringBoot依賴包)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/>
</parent>
<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>
</dependencies>
2. 創(chuàng)建HelloWorldApplication.java文件(在com.sst.cx包下)
package com.sst.cx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloWorldApplication {
public static void main( String[] args ) {
SpringApplication.run(HelloWorldApplication.class, args);
}
}
方式2(創(chuàng)建Spring項(xiàng)目)推薦
會(huì)自動(dòng)在pom.xml添加SpringBoot依賴笑窜,并自動(dòng)在com.sst.cx包下創(chuàng)建項(xiàng)目名+Application.java文件(內(nèi)容同上)。
===》2. 創(chuàng)建HelloController.java文件(在com.sst.cx.controller包下)
package com.sst.cx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@ResponseBody // 將方法的返回內(nèi)容作為頁(yè)面內(nèi)容登疗。不使用該注解時(shí)排截,會(huì)使用該方法的返回值對(duì)應(yīng)的同名html文件作為顯示頁(yè)面。
@RequestMapping("/hello") // 映射路徑為/hello辐益,在瀏覽器中使用http://localhost/hello可訪問(wèn)到断傲。
public String hello() {
return "Hello World!";
}
}
===》3. 運(yùn)行項(xiàng)目,在瀏覽器中輸入http://127.0.0.1:8080/hello智政。
內(nèi)置了Tomcat(不再需要部署到Tomcat)认罩,可以直接運(yùn)行。
2. starter機(jī)制
Spring項(xiàng)目在創(chuàng)建后想要運(yùn)行续捂,需要:導(dǎo)入各種依賴jar包垦垂、添加許多xml配置、部署到Tomcat服務(wù)器中牙瓢。
SpringBoot項(xiàng)目在創(chuàng)建后可以直接運(yùn)行(不用編寫(xiě)任何代碼劫拗、不用進(jìn)行任何配置),這都要?dú)w功于starter機(jī)制一罩。
SpringBoot將企業(yè)應(yīng)用研發(fā)中的各種場(chǎng)景都抽取出來(lái) 做成一個(gè)個(gè)的starter依賴包(整合了該場(chǎng)景下所有可能用到的依賴杨幼,并提供了大量的默認(rèn)/自動(dòng)配置),開(kāi)發(fā)者只需要在Maven的pom.xml中添加相應(yīng)的starter即可(SpringBoot就能自動(dòng)掃描到要加載的信息并啟動(dòng)相應(yīng)的默認(rèn)配置)聂渊。
1. SpringBoot官方提供的starter依賴包以spring-boot-starter-xxx方式命名差购。
spring-boot-starter-parent
spring-boot-starter-web
spring-boot-starter-test
spring-boot-starter-redis
spring-boot-starter-data-mongodb
spring-boot-starter-data-elasticsearch
2. 自定義的starter依賴包(第三方技術(shù)廠商提供 或 開(kāi)發(fā)員自己創(chuàng)建)以xxx-spring-boot-starter方式命名。
druid-spring-boot-starter
mybatis-spring-boot-starter
- spring-boot-starter-parent
所有SpringBoot項(xiàng)目的父級(jí)依賴(即所有SpringBoot項(xiàng)目都需要添加該父依賴):統(tǒng)一管理項(xiàng)目?jī)?nèi)的部分常用依賴欲逃;統(tǒng)一管理其他starter的版本(該依賴又被稱為SpringBoot的版本仲裁中心)。
該依賴包主要提供了以下特性:
1. 默認(rèn)JDK版本(Java 8)
2. 默認(rèn)字符集(UTF-8)
3. 依賴管理功能
4. 資源過(guò)濾
5. 默認(rèn)插件配置
6. 識(shí)別 application.properties 和 application.yml 類型的配置文件
===》查看源碼可知
其有一個(gè)父級(jí)依賴:spring-boot-dependencies饼暑。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.5</version>
</parent>
查看spring-boot-dependencies的pom.xml內(nèi)容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.5</version>
<packaging>pom</packaging>
....
<!-- 負(fù)責(zé)定義依賴稳析、插件的版本號(hào) -->
<properties>
<activemq.version>5.16.1</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.88</appengine-sdk.version>
<artemis.version>2.15.0</artemis.version>
<aspectj.version>1.9.6</aspectj.version>
<assertj.version>3.18.1</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
....
</properties>
<!-- 負(fù)責(zé)管理依賴 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-amqp</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-blueprint</artifactId>
<version>${activemq.version}</version>
</dependency>
...
</dependencies>
</dependencyManagement>
<build>
<!-- 負(fù)責(zé)管理插件 -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${build-helper-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>${flyway.version}</version>
</plugin>
...
</plugins>
</pluginManagement>
</build>
</project>
- spring-boot-starter-web
為Web開(kāi)發(fā)提供了所有依賴:
1. spring-boot-starter(核心啟動(dòng)器)
spring-boot
spring-boot-autoconfigure
spring-boot-starter-logging(log日志)
logback-classic
log4j-to-slf4j
jul-to-slf4j
jakarta.annotation-api
snakeyaml
2. spring-boot-starter-tomcat(Tomcat服務(wù)器)
3. spring-boot-starter-json(jackson)
4. spring-web(SpringFramework)
spring-beans
5. spring-webmvc
spring-aop
spring-context
spring-expression
為SpringMVC提供了大量默認(rèn)配置
1. 引入了ContentNegotiatingViewResolver和BeanNameViewResolver(視圖解析器)
2. 對(duì)包括WebJars在內(nèi)的靜態(tài)資源的支持
3. 自動(dòng)注冊(cè)Converter洗做、GenericConverter、Formatter(轉(zhuǎn)換器和格式化器)
4. 對(duì)HttpMessageConverters的支持(Spring MVC中用于轉(zhuǎn)換HTTP請(qǐng)求和響應(yīng)的消息轉(zhuǎn)換器)
5. 自動(dòng)注冊(cè) MessageCodesResolver(用于定義錯(cuò)誤代碼生成規(guī)則)
6. 支持對(duì)靜態(tài)首頁(yè)(index.html)的訪問(wèn)
7. 自動(dòng)使用 ConfigurableWebBindingInitializer
使用(只需在pom.xml中添加依賴:spring-boot-starter-web):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/>
</parent>
<dependencies>
<!--導(dǎo)入 spring-boot-starter-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
</dependencies>
在終端執(zhí)行如下命令彰居,可查看項(xiàng)目的依賴樹(shù)
mvn dependency:tree
自定義starter(命名規(guī)則:xxx-spring-boot-starter)
將獨(dú)立于業(yè)務(wù)代碼之外的功能模塊封裝成一個(gè)starter诚纸,便于復(fù)用。
步驟:
===》1. 創(chuàng)建一個(gè)SpringBoot項(xiàng)目陈惰,修改pom文件
添加spring-boot-autoconfigure依賴畦徘,可根據(jù)功能添加其他依賴。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
===》2. 創(chuàng)建HelloProperties.java配置類
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
===》3. 創(chuàng)建HelloService.java
public class HelloService {
private String name;
private int age;
public HelloService(String name, int age) {
this.name = name;
this.age = age;
}
public void hello() {
System.out.println(name + " age:" + age);
}
}
===》4. 創(chuàng)建MyAutoConfiguration.java自動(dòng)配置類
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
public class MyAutoConfiguration {
@Autowired
private HelloProperties helloProperties;
@Bean
public HelloService helloService() {
return new HelloService(helloProperties.getName(), helloProperties.getAge());
}
}
===》5. 創(chuàng)建spring.factories文件(在resources/META-INF/目錄下)
在該文件中配置上面創(chuàng)建的自動(dòng)配置類抬闯。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sst.cx.config.MyAutoConfiguration
===》6. 在application.properties配置文件中可進(jìn)行默認(rèn)配置井辆。
===》7. 打包
放置到測(cè)試項(xiàng)目的resources/lib目錄下。
使用自定義的starter
===》1. 創(chuàng)建一個(gè)SpringBoot項(xiàng)目(勾選Web依賴)溶握,修改pom.xml文件
添加自定義的starter依賴
<dependency>
<groupId>com.sst.cx</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/hello-spring-boot-starter-0.0.1-SNAPSHOT.jar</systemPath>
</dependency>
===》2. 在appllication.properties/yml配置文件中杯缺,添加
hello.name=zhangsan
hello.age=12
===》3. 測(cè)試(TestController.java)
@Controller
public class TestController {
@Autowired
private HelloService helloService;
@ResponseBody
@RequestMapping("/hello")
public String hello() {
helloService.hello();
return "success";
}
}
在瀏覽器中訪問(wèn)http://127.0.0.1:8080/hello,控制臺(tái)會(huì)輸出:zhangsan age:12
3. YAML標(biāo)記語(yǔ)言(以數(shù)據(jù)為中心,比xml睡榆、json更適合作為配置文件)
只需在SpringBoot項(xiàng)目中引入spring-boot-starter-web或spring-boot-starter(二者都集成了SnakeYAML庫(kù))就可以使用YAML(以 .yml 或 .yaml 結(jié)尾)作為配置文件萍肆。
語(yǔ)法規(guī)則
1. 使用縮進(jìn)表示層級(jí)關(guān)系(不允許使用Tab鍵,只允許使用空格肉微;空格數(shù)不重要匾鸥,但同級(jí)元素必須左側(cè)對(duì)齊)。
2. 大小寫(xiě)敏感碉纳。
3. 使用"key:[空格]value"形式(空格不能省略)表示一個(gè)鍵值對(duì)。
例: url: www.baidu.com
4. 支持3種數(shù)據(jù)結(jié)構(gòu)(可任意組合嵌套):
1. 對(duì)象(鍵值對(duì)的集合:對(duì)象的每個(gè)屬性對(duì)應(yīng)一個(gè)鍵值對(duì))
寫(xiě)法1. 普通寫(xiě)法(使用縮進(jìn)表示:對(duì)象與屬性的層級(jí)關(guān)系)
website:
name: 張三
url: www.baidu.com
寫(xiě)法2. 行內(nèi)寫(xiě)法
website: {name: 張三,url: www.baidu.com}
2. 數(shù)組(一組按次序排列的值)
寫(xiě)法1. 普通寫(xiě)法(使用-表示:數(shù)組中的元素)
pets:
-dog
-cat
-pig
寫(xiě)法2. 行內(nèi)寫(xiě)法
pets: [dog,cat,pig]
3. 字面量(單個(gè)的不可拆分的值馏艾,如:數(shù)字劳曹、字符串、布爾值琅摩、日期)
直接寫(xiě)在鍵值對(duì)的value中即可铁孵,默認(rèn)情況下字符串是不需要使用單引號(hào)或雙引號(hào)的。
若字符串使用了單引號(hào)房资,則會(huì)對(duì)字符串的特殊字符進(jìn)行轉(zhuǎn)義(如:"hello\nworld"則會(huì)輸出hello\nworld)蜕劝。
若字符串使用了雙引號(hào),則不會(huì)轉(zhuǎn)義(如:"hello\nworld"則會(huì)進(jìn)行換行)轰异。
5. 文件組織結(jié)構(gòu)
一個(gè)YAML文件由一個(gè)或多個(gè)相互獨(dú)立的文檔組成岖沛,文檔之間使用“---”作為分隔符(只包含一個(gè)文檔時(shí)可省略)。
例(hello.yaml)
spring:
profiles: dev
datasource:
url: jdbc:mysql://localhost:3306/Test
username: root
password: 12345678
driver-class-name: com.mysql.cj.jdbc.Driver
---
website:
name: bianchengbang
url: www.biancheng.net
---
name: "張三 \n 李四"
4. 配置文件
- 默認(rèn)配置文件
SpringBoot項(xiàng)目啟動(dòng)時(shí)會(huì)將以下5個(gè)位置的application.properties或apllication.yml文件(文件名固定)作為默認(rèn)配置文件搭独,并讀取配置內(nèi)容婴削。
1. file:./config/*/
2. file:./config/
3. file:./
4. classpath:/config/
5. classpath:/
說(shuō)明:
1. 優(yōu)先級(jí)依次降低,相同位置的application.properties的優(yōu)先級(jí)高于application.yml牙肝。
2. file: 指項(xiàng)目的根目錄唉俗;classpath: 指項(xiàng)目的類路徑(即resources目錄)嗤朴。
3. 通常只使用第5種(在resources目錄下創(chuàng)建配置文件,并添加內(nèi)容來(lái)覆蓋默認(rèn)配置)虫溜。
4. Maven項(xiàng)目打包時(shí)雹姊,位于項(xiàng)目根目錄下的配置文件無(wú)法被打包進(jìn)項(xiàng)目的JAR包(即在jar包中失效)。
解決(3方式):
1. 在IDEA的運(yùn)行配置(Run/Debug Configuration)中衡楞,添加虛擬機(jī)參數(shù) -Dspring.config.additional-location=/my-application.yml吱雏,指定外部配置文件。
2. 在IDEA的運(yùn)行配置(Run/Debug Configuration)中寺酪,添加程序運(yùn)行參數(shù) --spring.config.additional-location=/my-application.yml坎背,指定外部配置文件。
3. 在主啟動(dòng)類中調(diào)用System.setProperty()方法添加系統(tǒng)屬性spring.config.additional-location寄雀,指定外部配置文件得滤。
例
===》創(chuàng)建項(xiàng)目,在項(xiàng)目根目錄下盒犹、類路徑的config目錄下懂更、類路徑下分別創(chuàng)建一個(gè)配置文件(application.yml文件)。
1. 項(xiàng)目根路徑下
#上下文路徑為 /abc
server:
servlet:
context-path: /abc
2. 類路徑的config目錄下
#端口號(hào)為8084
#上下文路徑為 /helloWorld
server:
port: 8084
servlet:
context-path: /helloworld
3. 類路徑下
#默認(rèn)配置
server:
port: 8080
===》MyController.java
package com.sst.cx.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@ResponseBody
@RequestMapping("/test")
public String hello() {
return "hello Spring Boot!";
}
}
===》根據(jù)優(yōu)先級(jí)可知:服務(wù)器端口為8084急膀;上下文路徑為/abc
使用瀏覽器訪問(wèn)http://localhost:8084/abc/test
- 外部配置文件
除了默認(rèn)配置文件沮协,SpringBoot還可以加載項(xiàng)目外部的配置文件。
指定外部配置文件的路徑(2種方式)
1. spring.config.location(將只加載外部配置文件卓嫂,默認(rèn)配置文件會(huì)失效)
使用命令:java -jar {JAR} --spring.config.location={外部配置文件全路徑}
2. spring.config.additional-location(外部配置文件的優(yōu)先級(jí)最高)
使用命令:java -jar {JAR} --spring.config.additional-location={外部配置文件全路徑}
- 配置加載順序
SpringBoot項(xiàng)目不僅可以通過(guò)配置文件進(jìn)行配置慷暂,還可以通過(guò)環(huán)境變量、命令行參數(shù)等形式進(jìn)行配置晨雳。
SpringBoot會(huì)加載以下所有形式的配置(優(yōu)先級(jí)由高到低):
1. 命令行參數(shù)
SpringBoot中的所有配置都可以通過(guò)命令行參數(shù)進(jìn)行指定行瑞。
命令格式:java -jar {Jar文件名} --{參數(shù)1}={參數(shù)值1} --{參數(shù)2}={參數(shù)值2}
2. 來(lái)自java:comp/env的JNDI 屬性
3. Java系統(tǒng)屬性(System.getProperties())
4. 操作系統(tǒng)的環(huán)境變量
5. RandomValuePropertySource配置的random.*屬性值
6. 配置文件(.yml/.properties文件)
SpringBoot啟動(dòng)時(shí),會(huì)自動(dòng)加載JAR包內(nèi)部及JAR包所在目錄指定位置的配置文件(.yml/.properties文件)餐禁。
下圖(配置文件的加載順序)的說(shuō)明:
1. /myBoot:表示JAR包所在目錄
2. /childDir:表示JAR包所在目錄下config目錄的子目錄
3. JAR:表示SpringBoot項(xiàng)目打包生成的JAR包血久;
4. 數(shù)字:表示該配置文件的優(yōu)先級(jí),數(shù)字越小 優(yōu)先級(jí)越高 越先被加載(后加載的相同屬性會(huì)被忽略)帮非。
5. 同一位置下氧吐,Properties文件優(yōu)先級(jí)高于YAML文件。
7. @Configuration注解修飾的配置類上的@PropertySource指定的配置文件
8. 通過(guò)SpringApplication.setDefaultProperties指定的默認(rèn)屬性
例(命令行參數(shù))
java -jar hello-0.0.1-SNAPSHOT.jar --server.port=8081 --server.servlet.context-path=/hello
說(shuō)明:
1. server.port:指定服務(wù)器端口
2. server.servlet.context:上下文路徑(項(xiàng)目的訪問(wèn)路徑)
- 配置綁定(把配置文件中的值綁定到JavaBean對(duì)象的屬性中)
步驟:
1. 將配置信息存放在配置文件中末盔。
如果將所有的配置都集中在application.properties/yml配置文件中筑舅,會(huì)十分臃腫、難以維護(hù)庄岖。通常會(huì)將與SpringBoot無(wú)關(guān)的自定義配置提取到一個(gè)單獨(dú)的配置文件(如:resources/person.properties)中豁翎,然后給類添加@PropertySource注解指向該配置文件。
/*
例:
@Component
@ConfigurationProperties(prefix="person") // 將JavaBean屬性和配置文件的值進(jìn)行綁定
@PropertySource(value = "classpath:person.properties") // 指定配置文件
public class Person{}
*/
2. 在代碼中給類添加注解進(jìn)行綁定隅忿。
1. @ConfigurationProperties注解(修飾類:用于將配置文件的多個(gè)配置綁定到類的屬性中)
支持松散綁定/松散語(yǔ)法(如:配置文件中的person.firstName心剥、person.first-name邦尊、person.first_name、PERSON_FIRST_NAME都可以綁定到Person類的firstName屬性)优烧。
不支持SpEL表達(dá)式蝉揍。
支持所有類型數(shù)據(jù)的封裝(如: 基礎(chǔ)數(shù)據(jù)類型、類畦娄、Map又沾、List、Set)熙卡。
例:
@Component
@ConfigurationProperties(prefix="person")
public class Person{}
2. @Value注解(修飾屬性杖刷,用于將配置文件中的某一個(gè)配置綁定到屬性中)
不支持松散綁定。
支持SpEL表達(dá)式驳癌。
只支持基本數(shù)據(jù)類型(字符串滑燃、布爾值、整數(shù))颓鲜。
例:
@Component
public class Person {
@Value("${person.name}")
private String name;
}
例
===》在application.yml配置文件中(若為.properties文件則為:person.age=10形式)
person:
name: 張三
age: 10
boss: false
birth: 1949/10/1
maps: { k1: v1,k2: 12 }
lists:
‐ 張三
‐ 李四
dog:
name: 初一
age: 2
===》Person類
@Component // 類必須在Ioc容器中表窘。
@ConfigurationProperties(prefix="person") // 將配置文件中以person前綴開(kāi)頭的配置綁定到類的屬性中。
public class Person{
private String name;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
...省略set甜滨、get方法
}
===》Dog類
public class Dog {
private String name;
private String age;
...省略set乐严、get方法
}
===》HelloController控制器類
@Controller
public class HelloController {
@Autowired
private Person person;
@ResponseBody
@RequestMapping("/hello")
public Person hello() {
return person;
}
}
在瀏覽器中輸入:http://localhost:8081/hello
- 導(dǎo)入Spring配置(默認(rèn)情況下,Spring的.xml配置文件不會(huì)被SpringBoot識(shí)別)
2種方式:
1. 使用@ImportResource注解加載Spring的xml配置文件衣摩。
首先在類路徑(resources目錄)下創(chuàng)建beans.xml昂验,然后在主啟動(dòng)類中添加@ImportResource(locations = {"classpath:/beans.xml"})
2. 使用全注解方式加載Spring配置。
在使用@Configuration注解修飾的配置類中艾扮,使用@Bean注解向容器中注入JavaBean凛篙。
例:
@Configuration // 定義一個(gè)配置類(替代.xml配置文件)
public class MyAppConfig {
// @Bean修飾的方法會(huì)被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類掃描,構(gòu)建Bean并注入到容器中栏渺。
// 等價(jià)于 <bean id="personService" class="PersonServiceImpl"></bean>
@Bean // 等價(jià)于xml文件的Bean元素,id為方法名锐涯,class為返回值類型
public PersonService personService() {
return new PersonServiceImpl();
}
}
例(@ImportResource注解 方式加載)
===》beans.xml(resources目錄下)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="personService" class="com.sst.cx.service.impl.PersonServiceImpl"></bean>
</beans>
===》PersonService.java
public interface PersonService {
public Person getPersonInfo();
}
===》PersonServiceImpl.java
public class PersonServiceImpl implements PersonService {
@Autowired
private Person person;
@Override
public Person getPersonInfo() {
return person;
}
}
===》HelloworldApplicationTests.java(測(cè)試文件)
@SpringBootTest
class HelloworldApplicationTests {
@Autowired
Person person;
// IOC 容器
@Autowired
ApplicationContext ioc;
@Test
public void testHelloService() {
// 校驗(yàn) IOC 容器中是否包含組件 personService
boolean b = ioc.containsBean("personService");
if (b) {
System.out.println("personService 已經(jīng)添加到 IOC 容器中");
} else {
System.out.println("personService 沒(méi)添加到 IOC 容器中");
}
}
@Test
void contextLoads() {
System.out.println(person);
}
}
===》HelloworldApplication.java(在主啟動(dòng)類中添加@ImportResource注解)
@ImportResource(locations = {"classpath:/beans.xml"}) // 將beans.xml加載到項(xiàng)目中
@SpringBootApplication
public class HelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}
}
- 配置Profile(多環(huán)境)
通常程序會(huì)運(yùn)行在多套環(huán)境(開(kāi)發(fā)磕诊、測(cè)試、生產(chǎn))下纹腌,每套環(huán)境的配置不同(如:數(shù)據(jù)庫(kù)地址霎终、服務(wù)器端口、日志級(jí)別 等)缸夹。如果每次打包時(shí)靠手動(dòng)修改代碼來(lái)實(shí)現(xiàn)变隔,繁瑣且易錯(cuò)肚吏。可使用Profile功能來(lái)實(shí)現(xiàn)動(dòng)態(tài)切換環(huán)境(2種方式):
方式1. yml多文檔方式
在一個(gè)yml文件中每個(gè)分隔符隔開(kāi)的文檔對(duì)應(yīng)一套環(huán)境广凸。
方式2. 多profile文件方式
創(chuàng)建多個(gè)環(huán)境配置文件(每個(gè)環(huán)境配置文件對(duì)應(yīng)一套環(huán)境)阅茶。
切換環(huán)境的方法:
1. 配置文件中手動(dòng)切換
2. 虛擬機(jī)參數(shù): 在VM options指定: -Dspring.profiles.active=dev
3. 命令行參數(shù): java-jar xxx.jar --spring.profiles.active=dev
例(yml多文檔方式)
在application.yml配置文件中,添加:
#默認(rèn)配置
server:
port: 8080
#切換配置
spring:
profiles:
active: test #設(shè)置當(dāng)前環(huán)境
---
#開(kāi)發(fā)環(huán)境
server:
port: 8081
spring:
config:
activate:
on-profile: dev
---
#測(cè)試環(huán)境
server:
port: 8082
spring:
config:
activate:
on-profile: test
---
#生產(chǎn)環(huán)境
server:
port: 8083
spring:
config:
activate:
on-profile: prod
例(多profile文件方式)
===》創(chuàng)建application-dev.properties
server.port = 8080
===》創(chuàng)建application-test.properties
server.port = 8081
===》創(chuàng)建application-pro.properties
server.port = 8082
===》在application.properties配置文件中
spring.profiles.active = dev #設(shè)置當(dāng)前環(huán)境谅海,各環(huán)境配置文件的后綴脸哀。
- 自動(dòng)配置原理
SpringBoot通過(guò)注解(而不是xml文件的方式)來(lái)實(shí)現(xiàn)自動(dòng)/默認(rèn)配置。SpringBoot在啟動(dòng)時(shí)從類路徑下的META-INF/spring.factories中獲取EnableAutoConfiguration指定的所有自動(dòng)配置類扭吁,導(dǎo)入到容器中生效撞蜂。
在SpringBoot項(xiàng)目的啟動(dòng)類中有一個(gè)@SpringBootApplication注解(核心注解,一個(gè)組合注解)侥袜。
===》@SpringBootApplication注解蝌诡,定義如下
@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}
)}
)
public @interface SpringBootApplication {
...
}
===》@EnableAutoConfiguration注解,定義如下
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
...
}
SpringBoot通過(guò)@EnableAutoConfiguration注解開(kāi)啟自動(dòng)配置(掃描jar包下的spring.factories文件枫吧,文件中包含了自動(dòng)配置類)浦旱。
該注解導(dǎo)入了EnableAutoConfigurationImportSelector類的selectimports方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
通過(guò)getCandidateConfiguration方法,獲取配置文件列表由蘑。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
loadFactoryNames方法會(huì)加載所有META-INF下有spring.factories文件的jar包闽寡,并根據(jù)spring.factories文件中的配置,去加載相應(yīng)的類尼酿。
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
Map<String, List<String>> result = new HashMap();
try {
Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Map.Entry<?, ?> entry = (Map.Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result);
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
===》@import
該注解導(dǎo)入了AutoConfigurationImportSelector類爷狈,這個(gè)類中有一個(gè)很重要的方法:selectImports(),它幾乎涵蓋了組件自動(dòng)裝配的所有處理邏輯裳擎,包括獲得候選配置類涎永、配置類去重、排除不需要的配置類鹿响、過(guò)濾等羡微,最終返回符合條件的自動(dòng)配置類的全限定名數(shù)組。
例(spring.factories文件)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sst.cx.config.MyAutoConfiguration,\
com.sst.cx.config.MyAutoConfiguration2
例:
當(dāng)項(xiàng)目中需要使用依賴jar包中類的實(shí)例惶我,只需創(chuàng)建一個(gè)該類類型的屬性妈倔,并使用@Autowired或@Resource注解標(biāo)注(會(huì)注入到容器中)。
5. 日志(記錄運(yùn)行情況绸贡、定位問(wèn)題)
日志框架分為兩類:
1. 日志抽象層(為日志功能提供了一套標(biāo)準(zhǔn)規(guī)范的JavaAPI)
1. JCL(Jakarta Commons Logging)
2. SLF4j(Simple Logging Facade for Java)目前最流行
可靈活使用占位符進(jìn)行參數(shù)占位:簡(jiǎn)化代碼盯蝴、可讀性更好。
3. jboss-logging
2. 日志實(shí)現(xiàn)
1. Log4j
2. JUL(java.util.logging)
3. Log4j2
4. Logback(SLF4j的原生實(shí)現(xiàn)框架)
和Log4j同一個(gè)作者听怕,用來(lái)代替Log4j捧挺,擁有比Log4j更多的優(yōu)點(diǎn)特性、更強(qiáng)的性能尿瞭。
通常情況下闽烙,日志功能由一個(gè)日志抽象層和一個(gè)日志實(shí)現(xiàn)組合而成(SpringBoot選用的是:SLF4J+Logback)声搁。
- 使用SLF4J
使用步驟:
1. 在項(xiàng)目中導(dǎo)入SLF4J框架和一個(gè)日志實(shí)現(xiàn)框架(如:Logback)。
2. 調(diào)用日志時(shí),應(yīng)調(diào)用日志抽象層的方法研儒,而不是直接調(diào)用日志實(shí)現(xiàn)層的方法。
例:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
// 調(diào)用SLF4J的info()方法独令,而非直接調(diào)用logback的方法端朵。
logger.info("Hello World");
}
}
從下圖的SLF4J官方方案可以看出:
1. Logback作為Slf4j的原生實(shí)現(xiàn)框架。當(dāng)項(xiàng)目使用SLF4J+Logback組合記錄日志時(shí)燃箭,只需要引入SLF4J冲呢、Logback的Jar包即可;
2. Log4j雖然和Logback屬于同一個(gè)作者招狸,但Log4j的出現(xiàn)要早于SLF4J碗硬,因而Log4j沒(méi)有直接實(shí)現(xiàn)SLF4J。當(dāng)項(xiàng)目使用SLF4J+Log4j組合記錄日志時(shí)瓢颅,不但需要引入SLF4J、Log4j 的Jar包弛说,還必須引入它們之間的適配層(承上啟下:既要實(shí)現(xiàn)SLF4J的方法挽懦,還要有調(diào)用Log4j的方法):slf4j-log4j12.jar。
3. 當(dāng)項(xiàng)目使用SLF4J+JUL組合記錄日志時(shí)木人,與SLF4J+Log4j一樣信柿,不但需要引入SLF4J冀偶、JUL 的對(duì)應(yīng)的Jar包,還要引入適配層:slf4j-jdk14.jar渔嚷。
每一個(gè)日志實(shí)現(xiàn)框架都有自己的配置文件进鸠。使用SLF4J記錄日志時(shí),應(yīng)該使用日志實(shí)現(xiàn)框架的配置文件形病。
- 統(tǒng)一各依賴包中的日志框架
通常客年,一個(gè)項(xiàng)目會(huì)依賴于各種框架,每個(gè)框架記錄日志所使用的日志框架各不相同漠吻。如:Spring Boot(slf4j+logback)量瓜、Spring(commons-logging)、Hibernate(jboss-logging)途乃。
因此绍傲,需要統(tǒng)一日志框架的使用:
1. 使用 各替換包 替換 項(xiàng)目中原來(lái)的全部日志實(shí)現(xiàn)框架(分為2步:去除原框架;引入相應(yīng)的替換包)耍共。
替換包包含了 被替換的日志框架中的所有類(保證應(yīng)用不會(huì)報(bào)錯(cuò))烫饼,但使用的是SLF4J的API(達(dá)到統(tǒng)一日主框架的目的)。
如:log4j-over-slf4j替換Log4j试读、jul-to-slf4j.jar替換JUL
2. 導(dǎo)入SLF4J實(shí)現(xiàn)杠纵。
SpringBoot項(xiàng)目
spring-boot-starter(核心啟動(dòng)器)引入了spring-boot-starter-logging。spring-boot-starter-logging引入了 logback-classic(SLF4J的實(shí)現(xiàn))鹏往、 log4j-to-slf4j(log4j的替換包)淡诗、jul-to-slf4j(JUL的替換包)。
所以引入spring-boot-starter就完成了:引入替換包和導(dǎo)入SLF4J實(shí)現(xiàn) 這2步伊履。引入其他三方框架依賴時(shí)韩容,只需刪除其所依賴的日志框架,即可實(shí)現(xiàn)日志框架的統(tǒng)一唐瀑。例:
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-console</artifactId>
<version>${activemq.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
- 日志的配置(日志的級(jí)別群凶、日志的輸出格式)
- 默認(rèn)配置
SpringBoot項(xiàng)目中引入spring-boot-starter(引入了SLF4J+Logback,提供了大量默認(rèn)配置)就可以直接使用日志功能哄辣。
日志級(jí)別
日志的輸出都是分級(jí)別的请梢,當(dāng)一條日志信息的級(jí)別大于或等于配置文件的級(jí)別時(shí),才會(huì)對(duì)這條日志進(jìn)行記錄力穗。
輸出格式
可以通過(guò)日志參數(shù)對(duì)日志的輸出格式進(jìn)行修改毅弧。
序號(hào) | 常見(jiàn)的日志級(jí)別(優(yōu)先級(jí)依次升高) | 描述 |
---|---|---|
1 | trace | 追蹤,指明程序運(yùn)行軌跡当窗。(很少使用) |
2 | debug | 調(diào)試够坐。(實(shí)際項(xiàng)目中一般將其作為最低級(jí)別) |
3 | info | 輸出重要的信息。(使用較多) |
4 | warn | 警告。(使用較多) |
5 | error | 錯(cuò)誤信息元咙。(使用較多) |
序號(hào) | 常用的輸出格式 | 描述 |
---|---|---|
1 | %d{yyyy-MM-dd HH:mm:ss, SSS} | 日志創(chuàng)建時(shí)間(年月日 時(shí)分秒 毫秒) |
2 | %-5level | 日志級(jí)別(-5表示:左對(duì)齊且固定輸出5個(gè)字符梯影,不足則右邊補(bǔ)0) |
3 | %logger 或 %c | logger的名稱 |
4 | %thread 或 %t | 當(dāng)前線程的名稱 |
5 | %p | 日志輸出格式 |
6 | %message 或 %msg 或 %m | 日志內(nèi)容。logger.info("message")中的message |
7 | %n | 換行符 |
8 | %class 或 %C | Java類名 |
9 | %file 或 %F | 文件名 |
10 | %L | 出錯(cuò)的行號(hào) |
11 | %method 或 %M | 方法名 |
12 | %l | 語(yǔ)句所在的行數(shù)(包括類名庶香、方法名甲棍、文件名、行數(shù)) |
13 | hostName | 本地機(jī)器名 |
14 | hostAddress | 本地ip地址 |
例(測(cè)試SpringBoot項(xiàng)目的日志默認(rèn)級(jí)別)
package com.sst.cx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
Logger logger = LoggerFactory.getLogger(SpringBootMaven2Application.class);
logger.trace("trace 級(jí)別日志");
logger.debug("debug 級(jí)別日志");
logger.info("info 級(jí)別日志");
logger.warn("warn 級(jí)別日志");
logger.error("error 級(jí)別日志");
}
}
通過(guò)控制臺(tái)輸出結(jié)果可知:
1. SpringBoot項(xiàng)目的日志默認(rèn)級(jí)別為:info赶掖。
2. 日志輸出內(nèi)容默認(rèn)包含(占用一行感猛,依次包含):
創(chuàng)建時(shí)間(yyyy-MM-dd HH:mm:ss.SSS)
日志級(jí)別(如:WARN)
進(jìn)程 ID(如:945)
分隔符:---
線程名:方括號(hào)括起來(lái)(如:[ main])
logger的名稱(如:com.sst.cx.HelloApplication)
日志內(nèi)容(如:warn 級(jí)別日志)
例:
2015-10-29 11:37:21.940 INFO 945 --- [ main] com.sst.cx.HelloApplication : info 級(jí)別日志
- 修改默認(rèn)配置
在resources目錄下創(chuàng)建application.properties/yml,按需求添加如下內(nèi)容來(lái)覆蓋默認(rèn)配置:
#日志級(jí)別
logging.level.net.biancheng.www=trace
#設(shè)置日志輸出的位置-相對(duì)路徑(會(huì)在項(xiàng)目根目錄/my-log/myLog下自動(dòng)生成spring.log文件)
#logging.file.path=my-log/myLog
#設(shè)置日志輸出的位置-絕對(duì)路徑(會(huì)在項(xiàng)目所在磁盤(pán)根目錄/Users/cx/spring-boot/logging下自動(dòng)生成spring.log文件)
logging.file.path=/Users/cx/spring-boot/logging
#控制臺(tái)的日志輸出格式
logging.pattern.console=%d{yyyy-MM-dd hh:mm:ss} [%thread] %-5level %logger{50} - %msg%n
#spring.log日志文件輸出格式
logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} === - %msg%n
- 自定義日志配置
修改application.porperties/yml文件只能修改個(gè)別日志配置倘零,若修改更多的配置或使用更高級(jí)的功能唱遭,則需要通過(guò)日志實(shí)現(xiàn)框架的配置文件(Spring官方提供,開(kāi)發(fā)者只需將指定的配置文件放置到項(xiàng)目的類路徑即resourecs目錄下即可)來(lái)進(jìn)行配置(按需修改)呈驶。
日志框架 | 配置文件 |
---|---|
Logback | logback-spring.xml拷泽、logback-spring.groovy、logback.xml袖瞻、logback.groovy |
Log4j2 | log4j2-spring.xml司致、log4j2.xml |
JUL (Java Util Logging) | logging.properties |
日志框架的配置文件分為2類(在使用時(shí)大不相同):
1. 普通日志配置文件(即不帶srping標(biāo)識(shí)),如:logback.xml聋迎。
放置在項(xiàng)目的類路徑下后脂矫,配置文件會(huì)跳過(guò)SpringBoot直接被日志框架加載。
2. 帶有spring標(biāo)識(shí)的日志配置文件(SpringBoot推薦該方式)霉晕,如:logback-spring.xml庭再、log4j2-spring.xml。
放置在項(xiàng)目的類路徑下后牺堰,配置文件不會(huì)直接被日志框架加載拄轻,而是由SpringBoot對(duì)它們進(jìn)行解析,這樣就能使用SpringBoot的高級(jí)功能Profile(實(shí)現(xiàn)在不同的環(huán)境中使用不同的日志配置)伟葫。
例(logback.xml)普通日志配置文件
將logback.xml復(fù)制到SpringBoot項(xiàng)目的類路徑下(resources目錄下)恨搓,該配置文件配置內(nèi)容如下
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:設(shè)置為true(默認(rèn)),則當(dāng)配置文件發(fā)生改變后會(huì)被重新加載筏养。
scanPeriod:scan為true時(shí)此屬性生效斧抱。監(jiān)測(cè)配置文件是否發(fā)生修改的時(shí)間間隔(默認(rèn)1min)。如果沒(méi)有給出時(shí)間單位渐溶,默認(rèn)單位是毫秒辉浦。
debug:設(shè)置為true(默認(rèn)值為false)時(shí)會(huì)打印出logback內(nèi)部日志信息(實(shí)時(shí)查看logback運(yùn)行狀態(tài))。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- 定義日志的根目錄 -->
<property name="LOG_HOME" value="/Users/cx/spring-app/log"/>
<!-- 定義日志文件名稱 -->
<property name="appName" value="cx-spring-boot-logging"></property>
<!-- 定義控制臺(tái)輸出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志輸出格式:
%d:日期時(shí)間茎辐。
%thread:線程名盏浙。
%-5level:級(jí)別眉睹,從左顯示且5個(gè)字符寬度。
%logger{50}:logger名字最長(zhǎng)50個(gè)字符废膘,否則按照句點(diǎn)分割。
%msg:日志消息慕蔚。
%n:換行符丐黄。
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread]**************** %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<!-- 滾動(dòng)記錄文件,先將日志記錄到指定文件孔飒,當(dāng)符合某個(gè)條件時(shí)灌闺,將日志記錄到其他文件 -->
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名稱 -->
<file>${LOG_HOME}/${appName}.log</file>
<!--
當(dāng)發(fā)生滾動(dòng)時(shí),決定RollingFileAppender的行為坏瞄,涉及文件移動(dòng)和重命名桂对。
TimeBasedRollingPolicy: 最常用的滾動(dòng)策略,它根據(jù)時(shí)間來(lái)制定滾動(dòng)策略鸠匀,既負(fù)責(zé)滾動(dòng)也負(fù)責(zé)發(fā)出滾動(dòng)蕉斜。
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--
滾動(dòng)時(shí)產(chǎn)生的文件的存放位置及文件名稱 %d{yyyy-MM-dd}:按天進(jìn)行日志滾動(dòng)
%i:當(dāng)文件大小超過(guò)maxFileSize時(shí),按照i進(jìn)行文件滾動(dòng)
-->
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!--
可選節(jié)點(diǎn)缀棍,控制保留的歸檔文件的最大數(shù)量宅此,超出數(shù)量就刪除舊文件。假設(shè)設(shè)置每天滾動(dòng)爬范,且maxHistory是365父腕,則只保存最近365天的文件,刪除之前的舊文件青瀑。注意璧亮,刪除舊文件時(shí),那些為了歸檔而創(chuàng)建的目錄也會(huì)被刪除斥难。
-->
<MaxHistory>365</MaxHistory>
<!--
當(dāng)日志文件超過(guò)maxFileSize指定的大小時(shí)枝嘶,根據(jù)上面提到的%i進(jìn)行日志文件滾動(dòng) 注意此處配置SizeBasedTriggeringPolicy是無(wú)法實(shí)現(xiàn)按文件大小進(jìn)行滾動(dòng)的,必須配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志輸出格式: -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss} [ %thread ] ------------------ [ %-5level ] [ %logger{50} : %line ] -
%msg%n
</pattern>
</layout>
</appender>
<!--
logger主要用于存放日志對(duì)象蘸炸,也可以定義日志類型躬络、級(jí)別。
name:表示匹配的logger類型前綴(包路徑的前半部分)
level:要記錄的日志級(jí)別搭儒,包括:TRACE < DEBUG < INFO < WARN < ERROR
additivity:作用在于children-logger是否使用 rootLogger配置的appender進(jìn)行輸出穷当,false:表示只用當(dāng)前l(fā)ogger的appender-ref,true:表示當(dāng)前l(fā)ogger的appender-ref和rootLogger的appender-ref都有效淹禾。
-->
<!-- hibernate logger -->
<logger name="com.sst.cx" level="debug"/>
<!-- Spring framework logger -->
<logger name="org.springframework" level="debug" additivity="false"></logger>
<!--
root與logger是父子關(guān)系馁菜。沒(méi)有特別定義則默認(rèn)為root,任何一個(gè)類只會(huì)和一個(gè)logger對(duì)應(yīng)铃岔,要么是定義的logger汪疮,要么是root峭火。判斷的關(guān)鍵在于找到這個(gè)logger,然后判斷這個(gè)logger的appender和level智嚷。
-->
<root level="info">
<appender-ref ref="stdout"/>
<appender-ref ref="appLogAppender"/>
</root>
</configuration>
例(logback-spring.xml)帶有spring標(biāo)識(shí)的日志配置文件
1. 將上例中的logback.xml文件名修改為:logback-spring.xml卖丸。修改控制臺(tái)日志輸出,通過(guò)Profile實(shí)現(xiàn)不同的環(huán)境使用不同的日志輸出格式:
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<!--開(kāi)發(fā)環(huán)境 日志輸出格式-->
<springProfile name="dev">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
</springProfile>
<!--非開(kāi)發(fā)環(huán)境 日志輸出格式-->
<springProfile name="!dev">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
</springProfile>
</layout>
</appender>
2. 在SpringBoot項(xiàng)目的application.yml中盏道,激活開(kāi)發(fā)環(huán)境(dev)的 Profile稍浆,配置內(nèi)容如下:
#默認(rèn)配置
server:
port: 8080
#在這里切換環(huán)境,dev猜嘱、test衅枫、prod
spring:
profiles:
active: dev
---
#開(kāi)發(fā)環(huán)境
server:
port: 8081
spring:
config:
activate:
on-profile: dev
---
#測(cè)試環(huán)境
server:
port: 8082
spring:
config:
activate:
on-profile: test
---
#生產(chǎn)環(huán)境
server:
port: 8083
spring:
config:
activate:
on-profile: prod
6. 靜態(tài)資源映射
在Web項(xiàng)目中,為了讓頁(yè)面更美觀朗伶、更好的用戶體驗(yàn)弦撩,會(huì)使用到大量的靜態(tài)資源(如: JS、CSS论皆、HTML益楼、jQuery、Bootstrap等)纯丸。
SpringMVC項(xiàng)目導(dǎo)入靜態(tài)資源(將靜態(tài)資源文件復(fù)制到webapp目錄下)后需要配置靜態(tài)資源的映射偏形。
而SpringBoot項(xiàng)目則不需要,SpringBoot默認(rèn)提供了3種靜態(tài)資源映射規(guī)則:
1. WebJars映射(以Jar形式為Web項(xiàng)目提供資源文件)
SpringBoot項(xiàng)目是以Jar包的形式進(jìn)行部署的觉鼻,因此不存在webapp目錄俊扭。
WebJars可以將Web前端資源(JS,CSS 等)打成一個(gè)個(gè)的Jar包坠陈,然后將這些Jar包部署到Maven中央倉(cāng)庫(kù)中進(jìn)行統(tǒng)一管理萨惑。
只需在SpringBoot項(xiàng)目的pom.xml中引入依賴(訪問(wèn)WebJars官網(wǎng),找到所需Web前端資源的pom依賴)仇矾。
例(在SpringBoot項(xiàng)目中引入jquery庸蔼,只需在pom.xml中引入jquery依賴)
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
啟動(dòng)SpringBoot,在瀏覽器中訪問(wèn)“http://localhost:8080/webjars/jquery/3.6.0/jquery.js”訪問(wèn) jquery.js
所有通過(guò)WebJars引入的前端資源都存放在當(dāng)前項(xiàng)目類路徑下的/META-INF/resources/webjars/目錄中贮匕。
SpringBoot通過(guò)MVC的自動(dòng)配置類WebMvcAutoConfiguration為這些WebJars前端資源提供了默認(rèn)映射規(guī)則姐仅,部分源碼如下:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
// WebJars 映射規(guī)則
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
通過(guò)源碼可知,WebJars的映射路徑為"/webjars/**"(即所有訪問(wèn)"/webjars/**"的請(qǐng)求刻盐,都會(huì)去“classpath:/META-INF/resources/webjars/”下查找WebJars前端資源)掏膏。
2. 默認(rèn)資源映射
當(dāng)訪問(wèn)項(xiàng)目中的任意資源(即"/**")時(shí),SpringBoot會(huì)默認(rèn)從以下路徑(靜態(tài)資源目錄)中查找資源文件(優(yōu)先級(jí)依次降低)classpath表示resources目錄:
1. classpath:/META-INF/resources/
2. classpath:/resources/
3. classpath:/static/
4. classpath:/public/
3. 靜態(tài)首頁(yè)(歡迎頁(yè))映射
靜態(tài)資源目錄下的所有index.html被稱為靜態(tài)首頁(yè)或歡迎頁(yè)敦锌,會(huì)被"/**"映射(訪問(wèn)“/”或“/index.html”時(shí)會(huì)按優(yōu)先級(jí)查找 并跳轉(zhuǎn)到靜態(tài)首頁(yè))馒疹。
7. Thymeleaf模板引擎(用于渲染xml/xhtml/html5內(nèi)容的模板引擎,取代JSP)
Thymeleaf作為新一代Java模板引擎乙墙,相比傳統(tǒng)Java模板引擎(JSP颖变、Velocity生均、FreeMaker):
1. 支持HTML原型,其文件后綴為“.html”(因此可以直接被瀏覽器打開(kāi))腥刹。
2. 通過(guò)在html標(biāo)簽中增加額外的屬性來(lái)達(dá)到“模板+數(shù)據(jù)”的展示方式马胧。
特點(diǎn):
1. 動(dòng)靜結(jié)合(最大的特點(diǎn)):未啟動(dòng)Web應(yīng)用時(shí),也能在瀏覽器中顯示模板頁(yè)面(此時(shí)展示的是靜態(tài)內(nèi)容衔峰;通過(guò)Web應(yīng)用訪問(wèn)時(shí)會(huì)動(dòng)態(tài)替換掉靜態(tài)內(nèi)容)漓雅。
2. 開(kāi)箱即用:Thymeleaf 提供了 Spring 標(biāo)準(zhǔn)方言以及一個(gè)與 SpringMVC 完美集成的可選模塊,可以快速的實(shí)現(xiàn)表單綁定朽色、屬性編輯器、國(guó)際化等功能组题。
3. 多方言支持:它提供了 Thymeleaf 標(biāo)準(zhǔn)和 Spring 標(biāo)準(zhǔn)兩種方言葫男,可以直接套用模板實(shí)現(xiàn) JSTL、 OGNL 表達(dá)式崔列;必要時(shí)梢褐,開(kāi)發(fā)人員也可以擴(kuò)展和創(chuàng)建自定義的方言。
4. 與SpringBoot完美整合:SpringBoot為T(mén)hymeleaf提供了默認(rèn)配置赵讯,并且還為T(mén)hymeleaf設(shè)置了視圖解析器盈咳。
例
<!DOCTYPE html>
<!-- 聲明thymeleaf命名空間 -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--th:text為T(mén)hymeleaf屬性,用于展示文本內(nèi)容-->
<h1 th:text="迎您來(lái)到Thymeleaf">歡迎您訪問(wèn)靜態(tài)頁(yè)面 HTML</h1>
</body>
</html>
未啟動(dòng)Web應(yīng)用時(shí)边翼,直接使用瀏覽器打開(kāi)顯示:歡迎您訪問(wèn)靜態(tài)頁(yè)面HTML鱼响。
使用Web應(yīng)用訪問(wèn)時(shí),顯示:迎您來(lái)到Thymeleaf组底。
使用(語(yǔ)法規(guī)則)
首先在html標(biāo)簽中聲明thymeleaf空間(避免編輯器出現(xiàn)html驗(yàn)證錯(cuò)誤丈积,非必須):
<html xmlns:th="http://www.thymeleaf.org">
語(yǔ)法規(guī)則:
1. 標(biāo)準(zhǔn)表達(dá)式語(yǔ)法
1. 變量表達(dá)式(使用${}包裹的表達(dá)式)
1. 獲取對(duì)象的屬性、方法
${person.lastName}
2. 獲取內(nèi)置的基本對(duì)象及其屬性债鸡、方法
${#session.getAttribute('map')} 或 ${session.map}
內(nèi)置的基本對(duì)象:
1. #ctx :上下文對(duì)象江滨;
2. #vars :上下文變量;
3. #locale:上下文的語(yǔ)言環(huán)境厌均;
4. #request:HttpServletRequest 對(duì)象(僅在Web應(yīng)用中可用)唬滑。
5. #response:HttpServletResponse 對(duì)象(僅在Web應(yīng)用中可用)。
6. #session:HttpSession對(duì)象(僅在Web應(yīng)用中可用)棺弊。
7. #servletContext:ServletContext 對(duì)象(僅在Web應(yīng)用中可用)晶密。
3. 獲取內(nèi)置的工具對(duì)象
${#strings.equals('張三',name)}
內(nèi)置的工具對(duì)象:
1. strings(字符串工具對(duì)象)
常用方法:equals、equalsIgnoreCase镊屎、length惹挟、trim、toUpperCase缝驳、toLowerCase连锯、indexOf归苍、substring、replace运怖、startsWith拼弃、endsWith、contains摇展、containsIgnoreCase 等吻氧;
2. numbers(數(shù)字工具對(duì)象)
常用方法:formatDecimal 等;
3. bools(布爾工具對(duì)象)
常用方法:isTrue咏连、isFalse 等盯孙;
4. arrays(數(shù)組工具對(duì)象)
常用方法:toArray、length祟滴、isEmpty振惰、contains、containsAll 等垄懂;
5. lists/sets(List/Set集合工具對(duì)象)
常用方法:toList骑晶、size、isEmpty草慧、contains桶蛔、containsAll、sort 等漫谷;
6. maps(Map 集合工具對(duì)象)
常用方法:size仔雷、isEmpty、containsKey抖剿、containsValue 等朽寞;
7. dates(日期工具對(duì)象)
常用方法:format、year斩郎、month脑融、hour、createNow 等缩宜。
2. 選擇變量表達(dá)式(使用*{}包裹的表達(dá)式)
在變量表達(dá)式的基礎(chǔ)上增加了與th:object(用于存儲(chǔ)一個(gè)臨時(shí)變量肘迎,該變量只在該元素及其子元素中有效)的配合使用。
使用th:object存儲(chǔ)一個(gè)對(duì)象后锻煌,可以在其子元素中使用選擇變量表達(dá)式*{name}獲取該對(duì)象(*代表該對(duì)象)中的屬性妓布。子元素中仍可使用${}變量表達(dá)式。
例:
<div th:object="${session.user}" >
<p th:text="*{fisrtName}">firstname</p>
</div>
3. 鏈接表達(dá)式(使用@{}包裹的表達(dá)式)
用于:靜態(tài)資源引用宋梧、form表單請(qǐng)求(凡是鏈接都可以用鏈接表達(dá)式)匣沼。
1. 無(wú)參請(qǐng)求:@{/xxx}
2. 有參請(qǐng)求:@{/xxx(k1=v1,k2=v2)}
例:
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
4. 國(guó)際化表達(dá)式(使用#{}包裹的表達(dá)式)
用于國(guó)際化的場(chǎng)景。
th:text="#{msg}"
5. 片段引用表達(dá)式(使用~{}包裹的表達(dá)式)
用于在模板頁(yè)面中引用其他的模板片段捂龄。
方式1. ~{templatename::fragmentname} 推薦
方式2. ~{templatename::#id}
說(shuō)明:
1. templatename:模版名释涛,Thymeleaf會(huì)根據(jù)模版名解析完整路徑:/resources/templates/templatename.html加叁,要注意文件的路徑。
2. fragmentname:片段名唇撬,Thymeleaf通過(guò)th:fragment聲明定義代碼塊(即:th:fragment="fragmentname")
3. id:html的id選擇器它匕,使用時(shí)要在前面加上#號(hào),不支持class選擇器窖认。
2. th屬性
可以直接在HTML標(biāo)簽中使用豫柬。
常用的th屬性 | 描述 | 示例 |
---|---|---|
th:id | 替換id屬性 | <input id="html-id" th:id="thymeleaf-id" /> |
th:text | 文本替換,會(huì)轉(zhuǎn)義特殊字符 | <h1 th:text="hello world" >hello</h1> |
th:utext | 文本替換扑浸,不會(huì)轉(zhuǎn)義特殊字符 | <div th:utext="'<h1>hello world</h1>'" >世界你好</div> |
th:object | 在父標(biāo)簽中存儲(chǔ)一個(gè)對(duì)象烧给,子標(biāo)簽使用選擇變量表達(dá)式獲取該對(duì)象的屬性。 | <div th:object="${session.user}" ><p th:text="*{fisrtName}">firstname</p></div> |
th:value | 替換value屬性 | <input th:value = "${user.name}" /> |
th:with | 局部變量賦值運(yùn)算 | <div th:with="isEvens=${prodStat.count}%2==0" th:text="${isEvens}"></div> |
th:style | 設(shè)置樣式 | <div th:style="'color:#F00; font-weight:bold'">hello</div> |
th:onclick | 點(diǎn)擊事件 | <td th:onclick = "'getInfo()'"></td> |
th:each | 遍歷(支持Iterable喝噪、Map创夜、數(shù)組等)。 | <table><tr th:each="m:${session.map}"><td th:text="${m.getKey()}"></td><td th:text="${m.getValue()}"></td></tr></table> |
th:if | 根據(jù)條件判斷是否需要展示此標(biāo)簽 | <a th:if ="${userId == collect.userId}"> |
th:unless | 和 th:if 判斷相反仙逻,滿足條件時(shí)不顯示 | <div th:unless="${m.getKey()=='name'}" ></div> |
th:switch | 類似switch-case語(yǔ)句,與th:case配合使用涧尿,根據(jù)不同的條件展示不同的內(nèi)容系奉。 | <div th:switch="${name}"><span th:case="a">hello</span><span th:case="b">world</span></div> |
th:fragment | 類似jsp的tag,用來(lái)定義一段被引用或包含的模板片段姑廉。 | <footer th:fragment="footer">插入的內(nèi)容</footer> |
th:insert | 將使用th:fragment屬性指定的模板片段(包含標(biāo)簽)插入到當(dāng)前標(biāo)簽中缺亮。 | <div th:insert="commons/bar::footer"></div> |
th:replace | 將使用th:fragment屬性指定的模板片段(包含標(biāo)簽)替換當(dāng)前整個(gè)標(biāo)簽。 | <div th:replace="commons/bar::footer"></div> |
th:selected | select選擇框選中 | <select><option th:selected="${name=='a'}">hello</option><option th:selected="${name=='b'}">world</option></select> |
th:src | 替換html中的src屬性 | <img th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" /> |
th:inline | 內(nèi)聯(lián)屬性,有text桥言、none萌踱、javascript三種取值,在<script>標(biāo)簽中使用時(shí)号阿,js代碼中可以獲取到后臺(tái)傳遞頁(yè)面的對(duì)象。 | <script type="text/javascript" th:inline="javascript">var name = 'hello world';alert(name)</script> |
th:action | 替換表單提交的地址 | <form th:action="@{/user/login}" th:method="post"></form> |
公共頁(yè)面的抽取和引用
Web項(xiàng)目的頁(yè)面中通常會(huì)存在一些重復(fù)代碼(如:頭部導(dǎo)航欄、側(cè)邊菜單欄审姓、公共的js/css等)近弟。可以把這些公共頁(yè)面片段抽取出來(lái)存放在一個(gè)獨(dú)立的頁(yè)面中枯夜,然后再由其他頁(yè)面根據(jù)需要進(jìn)行引用(消除代碼重復(fù)弯汰、使頁(yè)面更簡(jiǎn)潔)。
1. 抽取公共頁(yè)面
將公共頁(yè)面片段抽取出來(lái)存放到一個(gè)獨(dú)立的頁(yè)面中湖雹,并使用th:fragment屬性命名咏闪。
<div th:fragment="fragment-name" id="fragment-id">
<span>公共頁(yè)面片段</span>
</div>
2. 引用公共頁(yè)面
可以通過(guò)以下3個(gè)屬性,將公共頁(yè)面片段引入到當(dāng)前頁(yè)面中摔吏。
1. th:insert:將代碼塊片段整個(gè)插入到使用了th:insert屬性的html標(biāo)簽中鸽嫂。
2. th:replace:將代碼塊片段整個(gè)替換使用了th:replace屬性的html標(biāo)簽中纵装。
3. th:include:將代碼塊片段包含的內(nèi)容插入到使用了th:include屬性的html標(biāo)簽中。
屬性值使用片段引用表達(dá)式引入引入頁(yè)面片段(通常溪胶,~{}可以省略)
方式1. ~{templatename::#id}:模板名::選擇器
方式2. ~{templatename::fragmentname}:模板名::片段名
行內(nèi)寫(xiě)法為: [[~{...}]] 會(huì)轉(zhuǎn)義特殊字符搂擦、[(~{...})] 不會(huì)轉(zhuǎn)義特殊字符。
例:
<div th:insert="commons::fragment-name"></div>
3. 傳遞參數(shù)
引用公共頁(yè)面片段時(shí)哗脖,通過(guò)以下2種方式將參數(shù)傳入到被引用的頁(yè)面片段中:
方式1(參數(shù)較多時(shí)使用該方式)明確指定參數(shù)名和參數(shù)值
模板名::選擇器名或片段名(參數(shù)1=參數(shù)值1,參數(shù)2=參數(shù)值2)
方式2(參數(shù)較少時(shí)使用該方式)
模板名::選擇器名或片段名(參數(shù)值1,參數(shù)值2)
例(查看th:insert瀑踢、th:replace、th:include3者的區(qū)別)
1. 在頁(yè)面 fragment.html 中引入 commons.html 中聲明的頁(yè)面片段
<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name"></div>
<!--th:insert id 選擇器引入-->
<div th:insert="commons::#fragment-id"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name"></div>
<!--th:replace id 選擇器引入-->
<div th:replace="commons::#fragment-id"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name"></div>
<!--th:include id 選擇器引入-->
<div th:include="commons::#fragment-id"></div>
2. 啟動(dòng) Spring Boot才避,使用瀏覽器訪問(wèn)fragment.html橱夭,右鍵查看頁(yè)面源碼:
<!--th:insert 片段名引入-->
<div>
<div id="fragment-id">
<span>公共頁(yè)面片段</span>
</div>
</div>
<!--th:insert id 選擇器引入-->
<div>
<div id="fragment-id">
<span>公共頁(yè)面片段</span>
</div>
</div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div id="fragment-id">
<span>公共頁(yè)面片段</span>
</div>
<!--th:replace id 選擇器引入-->
<div id="fragment-id">
<span>公共頁(yè)面片段</span>
</div>
------------------------------------------------
<!--th:include 片段名引入-->
<div>
<span>公共頁(yè)面片段</span>
</div>
<!--th:include id 選擇器引入-->
<div>
<span>公共頁(yè)面片段</span>
</div>
例(傳遞參數(shù))
<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name(var1='insert-name',var2='insert-name2')"></div>
<!--th:insert id 選擇器引入-->
<div th:insert="commons::#fragment-id(var1='insert-id',var2='insert-id2')"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name(var1='replace-name',var2='replace-name2')"></div>
<!--th:replace id 選擇器引入-->
<div th:replace="commons::#fragment-id(var1='replace-id',var2='replace-id2')"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name(var1='include-name',var2='include-name2')"></div>
<!--th:include id 選擇器引入-->
<div th:include="commons::#fragment-id(var1='include-id',var2='include-id2')"></div>
在公共頁(yè)面片段中使用:
<div th:fragment="fragment-name(var1,var2)" id="fragment-id">
<p th:text="'參數(shù)1:'+${var1} + '-------------------參數(shù)2:' + ${var2}">...</p>
</div>
SpringBoot項(xiàng)目中使用Thymeleaf
SpringBoot推薦使用Thymeleaf作為模板引擎(為其提供了大量默認(rèn)配置)。
使用步驟
1. 引入Thymeleaf依賴(在項(xiàng)目的pom.xml中添加spring-boot-starter-thymeleaf依賴)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2. 創(chuàng)建.html模板文件桑逝,并放置在項(xiàng)目類路徑(resources目錄)的templates目錄下棘劣。
例(hello.html):
<!DOCTYPE html>
<!--導(dǎo)入thymeleaf命名空間-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="'歡迎來(lái)到'+${name}"></h1>
</body>
</html>
3. 使用
創(chuàng)建HelloController.java,通過(guò)參數(shù)map傳遞數(shù)據(jù)到頁(yè)面中:
package com.sst.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Map<String, Object> map) {
map.put("name", "hello world");
return "hello";
}
}
啟動(dòng)SpringBoot楞遏,在瀏覽器中訪問(wèn):http://localhost:8080/hello
SpringBoot通過(guò)ThymeleafAutoConfiguration自動(dòng)配置類為T(mén)hymeleaf提供了一整套的自動(dòng)化配置方案茬暇。部分源碼如下:
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({ThymeleafProperties.class})
@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})
public class ThymeleafAutoConfiguration {
}
使用@EnableConfigurationProperties注解導(dǎo)入了ThymeleafProperties類(包含了和Thymeleaf相關(guān)的自動(dòng)配置屬性)。其部分源碼如下:
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
...
}
ThymeleafProperties通過(guò)@ConfigurationProperties注解將配置文件(application.properties/yml) 中前綴為spring.thymeleaf的配置和這個(gè)類中的屬性綁定寡喝。
ThymeleafProperties還提供了以下靜態(tài)變量:
1. DEFAULT_ENCODING:默認(rèn)編碼格式
2. DEFAULT_PREFIX:視圖解析器的前綴
3. DEFAULT_SUFFIX:視圖解析器的后綴
根據(jù)以上配置屬性可知:
1. Thymeleaf模板的默認(rèn)位置在resources/templates目錄下糙俗,默認(rèn)的后綴是html。
2. 只要將html頁(yè)面放在該目錄下预鬓,Thymeleaf就能自動(dòng)進(jìn)行渲染巧骚。
8. 國(guó)際化(為不同的國(guó)家/語(yǔ)言提供相應(yīng)的頁(yè)面和數(shù)據(jù))
步驟:
1. 創(chuàng)建國(guó)際化資源文件(在resources目錄的i18n目錄下)
文件名格式:基本名_語(yǔ)言_國(guó)家.properties
例(IDEA會(huì)自動(dòng)識(shí)別國(guó)際化資源文件并自動(dòng)添加Resouce Bundle目錄):
hello.properties:默認(rèn)
hello_zh_CN.properties:中文時(shí)生效
hello_en_US.properties:英語(yǔ)時(shí)生效
打開(kāi)任意一個(gè)國(guó)際化資源文件,切換為ResourceBundle模式(需要安裝ResourceBundle插件)格二,然后點(diǎn)擊“+”號(hào)創(chuàng)建所需的國(guó)際化屬性(需要進(jìn)行國(guó)際化的字段)劈彪。
2. 使用ResourceBundleMessageSource管理國(guó)際化資源文件。
在application.porperties/yml配置文件中添加spring.messages.basename來(lái)覆蓋默認(rèn)值(當(dāng)指定多個(gè)資源文件時(shí)顶猜,用逗號(hào)分隔)沧奴。
例:
spring.messages.basename=i18n.hello
3. 在頁(yè)面中使用國(guó)際化表達(dá)式#{}來(lái)獲取國(guó)際化內(nèi)容。
SpringBoot通過(guò)MessageSourceAutoConfiguration類對(duì)ResourceBundleMessageSource提供了默認(rèn)配置长窄。
===》MessageSourceAutoConfiguration類的部分源碼如下:
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration.ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = {};
// 將MessageSourceProperties以組件的形式添加到容器中扼仲,MessageSourceProperties下的每個(gè)屬性都與以spring.messages開(kāi)頭的屬性對(duì)應(yīng)。
@Bean
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
// Spring Boot會(huì)從容器中獲取MessageSourceProperties抄淑,讀取國(guó)際化資源文件的basename(基本名)屠凶、encoding(編碼)等信息并封裝到 ResourceBundleMessageSource中。
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
// 讀取國(guó)際化資源文件的basename (基本名),并封裝到ResourceBundleMessageSource中
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils
.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
}
// 讀取國(guó)際化資源文件的encoding (編碼),并封裝到ResourceBundleMessageSource中
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding(properties.getEncoding().name());
}
messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis(cacheDuration.toMillis());
}
messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
return messageSource;
}
...
}
從源碼可知:
1. SpringBoot將MessageSourceProperties以組件的形式添加到容器中肆资。
2. MessageSourceProperties的屬性與配置文件中以“spring.messages”開(kāi)頭的配置進(jìn)行了綁定矗愧。
3. SpringBoot從容器中獲取MessageSourceProperties組件,并從中讀取國(guó)際化資源文件的basename(文件基本名)、encoding(編碼)等信息唉韭,將它們封裝到 ResourceBundleMessageSource中夜涕。
4. SpringBoot將ResourceBundleMessageSource以組件的形式添加到容器中,進(jìn)而實(shí)現(xiàn)對(duì)國(guó)際化資源文件的管理属愤。
===》MessageSourceProperties類的源碼如下:
public class MessageSourceProperties {
private String basename = "messages";
private Charset encoding;
@DurationUnit(ChronoUnit.SECONDS)
private Duration cacheDuration;
private boolean fallbackToSystemLocale;
private boolean alwaysUseMessageFormat;
private boolean useCodeAsDefaultMessage;
public MessageSourceProperties() {
this.encoding = StandardCharsets.UTF_8;
this.fallbackToSystemLocale = true;
this.alwaysUseMessageFormat = false;
this.useCodeAsDefaultMessage = false;
}
...
}
從源碼可知:
1. MessageSourceProperties為basename女器、encoding等屬性提供了默認(rèn)值。
2. basename表示國(guó)際化資源文件的基本名住诸,其默認(rèn)值為“message”(即SpringBoot默認(rèn)會(huì)獲取類路徑下的message.properties以及message_XXX.properties作為國(guó)際化資源文件)驾胆。
3. 在application.porperties/yml配置文件中,使用配置參數(shù)“spring.messages.basename”即可重新指定國(guó)際化資源文件的基本名贱呐。
例
1. 在resources目錄的i18n目錄下創(chuàng)建
login.properties
login_en_US.properties
login_zh_CN.properties
2. 在application.porperties/yml配置文件中添加
application.porperties
spring.messages.basename=i18n.login
application.yml
spring:
messages:
basename: i18n/login
encoding: utf-8
3. 獲取國(guó)際化內(nèi)容
創(chuàng)建login.html丧诺,代碼如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta name="description" content="">
<meta name="author" content="ThemeBucket">
<link rel="shortcut icon" href="#" type="image/png">
<title>Login</title>
<!--將js css 等靜態(tài)資源的引用修改為 絕對(duì)路徑-->
<link href="css/style.css" th:href="@{/css/style.css}" rel="stylesheet">
<link href="css/style-responsive.css" th:href="@{/css/style-responsive.css}" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="js/html5shiv.js" th:src="@{/js/html5shiv.js}"></script>
<script src="js/respond.min.js" th:src="@{/js/respond.min.js}"></script>
<![endif]-->
</head>
<body class="login-body">
<div class="container">
<form class="form-signin" th:action="@{/user/login}" method="post">
<div class="form-signin-heading text-center">
<h1 class="sign-title" th:text="#{login.btn}">Sign In</h1>
<img src="/images/login-logo.png" th:src="@{/images/login-logo.png}" alt=""/>
</div>
<div class="login-wrap">
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
<input type="text" class="form-control" name="username" placeholder="User ID" autofocus
th:placeholder="#{login.username}"/>
<input type="password" class="form-control" name="password" placeholder="Password"
th:placeholder="#{login.password}"/>
<label class="checkbox">
<input type="checkbox" value="remember-me" th:text="#{login.remember}">
<span class="pull-right">
<a data-toggle="modal" href="#myModal" th:text="#{login.forgot}"> </a>
</span>
</label>
<button class="btn btn-lg btn-login btn-block" type="submit">
<i class="fa fa-check"></i>
</button>
<div class="registration">
<!--Thymeleaf 行內(nèi)寫(xiě)法-->
[[#{login.not-a-member}]]
<a class="" href="/registration.html" th:href="@{/registration.html}">
[[#{login.signup}]]
</a>
<!--thymeleaf 模板引擎的參數(shù)用()代替 ?-->
<br/>
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>|
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
</div>
</div>
<!-- Modal -->
<div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="myModal"
class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Forgot Password ?</h4>
</div>
<div class="modal-body">
<p>Enter your e-mail address below to reset your password.</p>
<input type="text" name="email" placeholder="Email" autocomplete="off"
class="form-control placeholder-no-fix">
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-default" type="button">Cancel</button>
<button class="btn btn-primary" type="button">Submit</button>
</div>
</div>
</div>
</div>
<!-- modal -->
</form>
</div>
<!-- Placed js at the end of the document so the pages load faster -->
<!-- Placed js at the end of the document so the pages load faster -->
<script src="js/jquery-1.10.2.min.js" th:src="@{/js/jquery-1.10.2.min.js}"></script>
<script src="js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
<script src="js/modernizr.min.js" th:src="@{/js/modernizr.min.js}"></script>
</body>
</html>
手動(dòng)切換語(yǔ)言
1. 區(qū)域信息解析器自動(dòng)配置
可以通過(guò)以下兩個(gè)對(duì)象對(duì)區(qū)域信息進(jìn)行切換奄薇,繼而切換語(yǔ)言驳阎。
1. Locale(區(qū)域信息對(duì)象)
2. LocaleResolver(區(qū)域信息解析器)容器中的組件,負(fù)責(zé)獲取區(qū)域信息對(duì)象
2. 手動(dòng)切換語(yǔ)言
1. 修改login.html中的切換語(yǔ)言鏈接馁蒂,在請(qǐng)求中攜帶國(guó)際化區(qū)域信息呵晚,代碼如下
<!--thymeleaf 模板引擎的參數(shù)用()代替 ?-->
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>|
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
2. 在com.sst.cx.component包下創(chuàng)建一個(gè)區(qū)域信息解析器MyLocalResolver沫屡,代碼如下
package com.sst.cx.component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
// 自定義區(qū)域信息解析器
public class MyLocalResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
// 獲取請(qǐng)求中參數(shù)
String l = request.getParameter("l");
// 獲取默認(rèn)的區(qū)域信息解析器
Locale locale = Locale.getDefault();
// 根據(jù)請(qǐng)求中的參數(shù)重新構(gòu)造區(qū)域信息對(duì)象
if (StringUtils.hasText(l)) {
String[] s = l.split("_");
locale = new Locale(s[0], s[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
3. 在com.sst.cx.config包下的MyMvcConfig中添加以下方法劣纲,將自定義的區(qū)域信息解析器以組件的形式添加到容器中,代碼如下:
// 將自定義的區(qū)域信息解析器以組件的形式添加到容器中
@Bean
public LocaleResolver localeResolver(){
return new MyLocalResolver();
}
===》SpringBoot在WebMvcAutoConfiguration類中為區(qū)域信息解析器進(jìn)行了自動(dòng)配置谁鳍,源碼如下:
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
@SuppressWarnings("deprecation")
public LocaleResolver localeResolver() {
if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.webProperties.getLocale());
}
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
Locale locale = (this.webProperties.getLocale() != null) ? this.webProperties.getLocale()
: this.mvcProperties.getLocale();
localeResolver.setDefaultLocale(locale);
return localeResolver;
}
從源碼可知:
1. 該方法默認(rèn)向容器中添加了一個(gè)LocaleResolver區(qū)域信息解析器組件,它會(huì)根據(jù)請(qǐng)求頭中攜帶的“Accept-Language”參數(shù)劫瞳,獲取相應(yīng)Locale區(qū)域信息對(duì)象倘潜。
2. 該方法上使用了@ConditionalOnMissingBean注解,其參數(shù)name的取值為 localeResolver(與該方法注入到容器中的組件名稱一致)志于,該注解的含義為:當(dāng)容器中不存在名稱為localResolver組件時(shí)涮因,該方法才會(huì)生效。即手動(dòng)向容器中添加一個(gè)名為“l(fā)ocaleResolver”的組件時(shí)伺绽,SpringBoot自動(dòng)配置的區(qū)域信息解析器會(huì)失效养泡,自定義的區(qū)域信息解析器則會(huì)生效。