SpringMVC

SpringMVC原理分析

Spring Boot學習

5、Hello World探究

1、POM文件

1、父項目

org.springframework.boot

spring-boot-starter-parent

2.0.2.RELEASE

?

他的父項目是:

org.springframework.boot

spring-boot-dependencies

2.0.2.RELEASE

../../spring-boot-dependencies

他才真正的管理springboot應用的所有依賴版本。

Spring Boot的版本仲裁中心:

以后我們導入依賴,默認不需要寫版本(沒有在dependencies里面的依賴需要我們手動寫上版本);

2、啟動器

org.springframework.boot

spring-boot-starter-web

spring-boot-starter-web

spring-boot-starter:spring-boot場景啟動器;幫我們導入了web模塊正常運行所依賴的組件;

Spring Boot將所有的功能場景都抽取出來,做成一個個starters(啟動器),只要在項目里面引入這些starter相關場景的所有依賴都會導入進來。要用什么功能,就導入什么場景的啟動器。

2、主程序類,主入口類

/**

* @author Alan

* @date 2018/5/12 16:11

* @SpringBootApplication 來標注一個主程序類,說明這是一個Spring Boot應用

*/

@SpringBootApplication

publicclassHelloWorldApplication{

publicstaticvoidmain(String[]args) {

//spring應用啟動起來

SpringApplication.run(HelloWorldApplication.class,args);

?? }

}

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

@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@interfaceSpringBootApplication{

@SpringBootConfiguration:Spring Boot的配置類

? 標注在某個類上,表示 這是一個Spring Boot的配置類;

? @Configuration:配置類上來標注這個注解;

? 配置類----配置文件;配置類也是一個組件:@Component

@EnableAutoConfiguration:開啟自動配置功能;

? 以前我們需要配置的東西,Spring Boot幫我們自動配置;@EnableAutoConfiguration告訴Spring開啟自動配置功能,這樣自動配置才能生效;

@AutoConfigurationPackage

@Import({AutoConfigurationImportSelector.class})

public@interfaceEnableAutoConfiguration{

? @AutoConfigurationPackage:自動配置包;

? @Import({Registrar.class}):

? Spring底層注釋@Import,給容器中導入一個組件;導入的組件由AutoConfigurationImportSelector.class指定。

? 將主配置類(@SpringBootApplication標注的類)的所在包及下面的所有組件掃描到Spring容器;

? @Import({Registrar.class}):

? 給容器中導入組件?

? AutoConfigurationImportSelector.class:導入哪些組件的選擇器

? 將所有需要的組件以全類名的方式返回;這些組件就會被添加到容器中;

? 會給容器中導入非常多的自動配置類(xxxAutoConfiguration);就是給容器中導入這個場景需要的所有組件,并配置好這些組件;

有了自動配置類,免去了我們手動編寫配置注入功能組件等工作;

? SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,class Loader)

? Spring Boot在啟動的時候,從類路徑 META-INFO/spring.facotries中獲取EnableAutoConfiguration指定的值;將這些值作為自動配置類導入到容器中,自動配置類就生效了,幫我們自動配置工作;

我們點一個webmvc進去,如下:

以前我們需要配置的東西都幫我們自動配置了,J2EE的整體整合解決方案和自動配置都在:

C:\Users\Alan.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.0.2.RELEASE\spring-boot-autoconfigure-2.0.2.RELEASE.jar

6、使用Spring Initializer快速創建Spring Boot項目

IDE都 支持使用Spring的創建向導快速創建一個Spring Boot項目;

選擇我們需要的模塊,向導會聯網創建Spring Boot項目;

默認生成的Spring Boot項目:

主程序已經生成好了

resources文件夾目錄結構

static: 保存所有的靜態資源;js、css、images;

templates:保存所有的模板頁面:(Spring Boot默認jar包使用嵌入式的Tomcat,默認不支持JSP頁面);可以使用模板引擎(thymeleaf、freemarker);

applications.properties:Spring Boot應用的配置文件;可以修改一些默認配置;

二、配置文件

1、配置文件

Spring Boot使用一個全局的配置文件,配置文件名是固定的:

application.properties

application.yml

配置文件的作用:修改Spring Boot自動配置的默認值;

Spring Boot在底層都給我們自動配置好了;

YAML(YAML Ain't Markup Language)

? YAML A Markup Language:是一個標記語言;

? YAML isn't Markup Language:不是一個標記語言;

標記語言:

? 以前的配置文件,大多是xxx.xml文件;

? YAML:以數據為中心,比json、xml更適合做配置文件;

YAML配置例子:

server:

? port: 8080

XML配置例子:

? ? 8080

2、YAML語法

1、基本語法

k:(空格)v :表示一對鍵值對(空格必須有)

以空格的縮進來控制層級關系;只要是左對齊的一列數據,都表示同一層級;

server:

? ? port: 8080

? ? path: /hello

屬性和值也是大小寫敏感的;

2、值的寫法

字面量:普通的值(數字、字符串、布爾)

? k: v :字面直接來寫;

? 字符串默認不用加上雙引號和單引號;

? “”:雙引號,不會轉義字符串里面的特殊字符,特殊字符會作為本身想表示的意思

? name: "zhangsan \n lisi":輸出zhangsan 換行 lisi

? ’‘:單引號:會轉義特殊字符,特殊字符最終只是一個普通字符串數據

? name: 'zhangsan \n lisi':輸出zhangsan \n lisi

對象、Map(屬性和值)(鍵值對):

? k: v:在下一行寫對象的屬性和值的關系,注意縮進;

? 對象還是k: v格式

friends:

? ? lastName: zhangsan

? ? age: 20

行內寫法:

friends: {lastName: zhangsan,age: 20}

數組(List、Set):

用- 值表示數組中的一個元素

pets:

- cat

- dog

- monkey

行內寫法:

pets: [cat,dog,monkey]

3、配置文件值注入

配置文件:

person:

? lastName: zhangsan

? age: 18

? boss: false

? birthday: 2017/12/12

? maps: {k1: v1,k2: v2}

? lists:

? - lisi

? - zhaoliu

? dog:

?? name: 小狗

?? age: 2

JavaBean:

/**

* @author Alan

* @date 2018/5/12 21:01

* 將配置文件中的每一個屬性值,映射到這個組件中

* @ConfigurationProperties:告訴SpringBoot將本類的所有屬性和配置文件中相關的配置綁定

* ? ?? prefix = "person" 配置文件中的哪個屬性進行一一映射

* 只有這個組件是容器中的組件,才能使用容器提供的@ConfigurationProperties功能

*/

@Component

@ConfigurationProperties(prefix="person")

publicclassPerson{

privateStringlastName;

privateIntegerage;

privateBooleanboss;

privateDatebirthday;

?

privateMapmaps;

privateListlists;

privateDogdog;

我們可以導入導入配置文件處理器,以后編寫配置就有提示了:


? ? ? ?

? ? ? ? ? ? org.springframework.boot

? ? ? ? ? ? spring-boot-configuration-processor

? ? ? ? ? ? true


單元測試例子:

packagecom.example.demo;

?

importcom.example.demo.bean.Person;

importorg.junit.Test;

importorg.junit.runner.RunWith;

importorg.springframework.beans.factory.annotation.Autowired;

importorg.springframework.boot.test.context.SpringBootTest;

importorg.springframework.test.context.junit4.SpringRunner;

?

/**

* SpringBoot單元測試

* 可以在測試期間很方便的類似編碼一樣進行自動注入

*/

@RunWith(SpringRunner.class)

@SpringBootTest

publicclassDemoApplicationTests{

? ? @Autowired

? ? Personperson;

?

? ? @Test

? ? publicvoidcontextLoads() {

? ? ? ? System.out.println(person);

? ? }

?

}

?

1、properties文件在idea中默認utf-8可能會亂碼

結果發現中文亂碼,需要進行設置:勾選Transparent native-to-ascii conversion,轉出ascii碼

這樣就不會亂碼了:

2、@Value與@ConfigurationProperties獲取值比較

@ConfigurationProperties@Value

功能批量注入配置文件中的屬性一個一個指定

松散綁定(松散語法)支持不支持

SpEL不支持支持

JSR303數據校驗支持不支持

復雜類型封裝支持不支持

配置文件yml還是properties他們都能獲取到值;

如果說,我們只是在業務邏輯中要獲取一下配置文件中的某項值,使用@Value;

如果說,我們編寫了一個JavaBean和配置文件進行映射,我們就直接使用@ConfigurationProperties;

3、配置文件注入值數據校驗

@Component

@ConfigurationProperties(prefix="person")

@Validated

publicclassPerson{

//lastName必須是郵箱格式,default message [不是一個合法的電子郵件地址]

@Email

//@Value("${person.last-name}")

privateStringlastName;

privateIntegerage;

4、@PropertySource與@ImportResource

@PropertySource:加載指定的配置文件

/**

* @author Alan

* @date 2018/5/12 21:01

* 將配置文件中的每一個屬性值,映射到這個組件中

* @ConfigurationProperties:告訴SpringBoot將本類的所有屬性和配置文件中相關的配置綁定

* ? ?? prefix = "person" 配置文件中的哪個屬性進行一一映射

* 只有這個組件是容器中的組件,才能使用容器提供的@ConfigurationProperties功能

* @ConfigurationProperties(prefix = "person")默認從全局配置文件中獲取值

*/

@PropertySource(value="classpath:person.properties")

@Component

@ConfigurationProperties(prefix="person")

//@Validated

publicclassPerson{

//lastName必須是郵箱格式,default message [不是一個合法的電子郵件地址]

//@Email

//@Value("${person.last-name}")

privateStringlastName;

privateIntegerage;

privateBooleanboss;

privateDatebirthday;

?

privateMapmaps;

privateListlists;

privateDogdog;

@ImportResource:導入Spring的配置文件,讓配置文件里面的內容生效

Spring Boot里面沒有Spring的配置文件,我們自己編寫的配置文件,也不能自動識別;

想讓Spring的配置文件生效,加載進來,@ImportResource標注在一個配置類上;

beans.xml:


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">

SpringBootApplication類:

//導入Spring的配置文件,使其生效

@ImportResource(locations={"classpath:beans.xml"})

@SpringBootApplication

publicclassDemoApplication{

?

? ? publicstaticvoidmain(String[]args) {

? ? ? ? SpringApplication.run(DemoApplication.class,args);

? ? }

}

test類:

@RunWith(SpringRunner.class)

@SpringBootTest

publicclassDemoApplicationTests{

? ? @Autowired

? ? Personperson;

?

? ? @Autowired

? ? ApplicationContextioc;

?

? ? @Test

? ? publicvoidhelloservice(){

? ? ? ? Booleanb=ioc.containsBean("helloservice");

? ? ? ? System.out.println(b);

? ? }

單元測試結果:

不來編寫Spring的配置文件:


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">

Spring Boot推薦的給容器中添加組件的方式:推薦使用全注解的方式

1、配置類======Spring配置文件

2、使用@Bean給容器中添加組件

/**

* @author Alan

* @date 2018/5/12 22:30

* @Configuration:指明當前類是一個配置文件,就是來替代之前的Spring配置文件

* 配置文件使用標簽添加組件

*/

@Configuration

publicclassMyAppConfig{

//將方法的返回值添加到容器中,容器中這個組件默認的id就是方法名

@Bean

publicHelloServicehelloService(){

System.out.println("@Bean給容器添加組件了...");

returnnewHelloService();

?? }

}

4、配置文件占位符

1、隨機數

${random.value}、${random.int}、${random.long}

${random.int(10)}、${random.int[1024,65536]}

2、占位符獲取之前配置的值,如果沒有可以使用:指定默認值

person.last-name=張三${random.uuid}

person.age=${random.int}

person.boss=true

person.birthday=2019/02/03

person.maps.k1=v1

person.maps.k2=v2

person.lists=a,b,c

person.dog.name=${person.hello:hello}小狗

person.dog.age=2

5、Profile

1、多profile文件

我們在主配置文件編寫的時候,文件名可以是application-{profile}.properties/yml

默認使用application.properties

2、yml支持多文檔塊方式

server:

? port: 8080

spring:

? profiles:

?? active: prod

---

server:

? port: 8083

spring:

? profiles: dev

---

server:

? port: 8084

spring:

? profiles: prod#指定屬于哪個環境

3、激活指定profile

? 1、在配置文件中指定spring.profiles.active=dev

? 2、命令行:

? java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev

? 可以直接在測試的時候,配置傳入命令行參數

?

利用idea的maven插件進行打包(雙擊package)

之后target目錄下會生成jar文件,target右鍵-show in explorer,然后地址欄輸入cmd,這樣就進入了target目錄,然后輸入如下命令:java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev

端口就啟動了dev下的端口號,而不是默認配置文件里面的prod端口號(8084)

3、虛擬機參數

? -Dspring.profiles.active=dev

6、配置文件的加載位置

Spring Boot啟動會掃描以下位置的application.properties或者application.yml文件作為Spring Boot的默認配置文件

-file:./config/

-file:./

-classpath:/config

-classpath:/

優先級,由高到低,高優先級的配置會覆蓋低優先級的配置;

Spring Boot從4個位置全局加載主配置文件;互補配置

我們還可以通過spring.config.location來改變默認的配置文件位置

項目打包好后,我們可以使用命令行參數的形式,啟動項目的時候指定配置文件的新位置;指定配置文件和默認加載的這些配置文件共同起作用,形成互補配置。解釋:主要是針對運維,比如項目打包好后是8084,但是需要改變端口號,我們只要命令行運行時加上--spring.config.location=G:/application.properties,這樣項目就可以通過8085訪問了,不需要重新打包jar包,通過加載外部配置文件即可辦到,比較方便。

比如在D盤新建一個配置文件,更改端口為8085:

IDEA-terminal:

cd target

D:\idea project\SpringBoot-02-helloworld\target>java -jar demo-0.0.1-SNAPSHOT.jar --spring.config.location=D:/application.properties

項目啟動時的端口就是8085了:

7、外部配置加載順序

1.命行參數

java -jar demo-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc

多個配置用空格分開,--配置項=值

2.來自 java: comp/env的ND屬性3.Java系統屬性( System getproperties0)4.操作系統環境變量

Random Value Property Source配置的 random:*屬性值

由jar包外向jar包內進行尋找;

優先加載帶profile的

6.jar包外部的 application- Profile) properties或 application yml(帶 spring profile)配置文件7.jar包內部的 application- profile) properties或 application yml(帶 spring profile配置文件

再來加載不帶profile的

8.jar包外部的 application properties或 application yml(不帶 spring profile)配置文件9.jar包內部的 application properties或 application yml(不帶 spring profile)配置文件

10.@ Configuration注解類上的@ PropertySource11.通過 SpringApplication. setDefaultproperties指定的默認屬性

8、自動配置原理

配置文件能寫什么?怎么寫?自動配置原理,參見:

https://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/htmlsingle/#appendix

1、自動配置原理:

1)Spring Boot啟動的時候,加載主配置類,開啟了自動配置功能@EnableAutoConfiguration

2)@EnableAutoConfiguration的作用:

利用AutoConfigurationImportSelector給容器中導入一些組件;

可以查看selectImports()方法的內容:

List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);獲取候選的配置

SpringFactoriesLoader.loadFactoryNames

掃描所有jar包路徑下的META-INF/spring.factories

把這些掃描到的這些文件的內容包裝成properties對象

從properties獲取EnableAutoConfiguration.class類名對應的值,然后把他們添加在容器中

將類路徑下的META-INF/spring.factories里面配置的EnableAutoConfiguration值加入到容器中;

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\

org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\

org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\

org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\

org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\

org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\

org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\

org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\

org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\

org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\

org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\

org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\

org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\

org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\

org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\

org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\

org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\

org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\

org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\

org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\

org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\

org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\

org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\

org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\

org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\

org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\

org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\

org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\

org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\

org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\

org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\

org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\

org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\

org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\

org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\

org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\

org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\

org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\

org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\

org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\

org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\

org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\

org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\

org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\

org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\

org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\

org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\

org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\

org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\

org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\

org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

每一個這樣的xxxAutoConfiguration類都是容器中的一個組件,到加入到容器中;用他們來做自動配置;

3)每一個自動配置類進行自動配置功能;

4)以HttpEncodingAutoConfiguration(Http編碼自動配置)為例解釋自動配置原理;

@Configuration//表示這是一個配置類,以前的配置文件一樣,也可以給容器中添加組件

?

@EnableConfigurationProperties({HttpEncodingProperties.class})//啟用指定類的ConfigurationProperties功能,將配置文件中對應的值和HttpEncodingProperties綁定起來;并把HttpEncodingProperties加入到ioc容器中

?

@ConditionalOnWebApplication(//sping底層@Conditional注解,根據不同的條件,如果滿足指定的條件,整個配置類里面的配置就會生效:判斷當前應用是否為web應用,如果是,當前配置類生效

type=Type.SERVLET

)

?

@ConditionalOnClass({CharacterEncodingFilter.class})//判斷當前項目有沒CharacterEncodingFilte類:SpringMVC中進行亂碼解決的過濾器;

?

//判斷文件是否存在某個配置:spring.http.encoding.enabled,如果不存在,判斷也是成立的,即使配置文件中不配置spring.http.encoding.enabled=true,也是默認生效的;

@ConditionalOnProperty(

prefix="spring.http.encoding",

value={"enabled"},

matchIfMissing=true

)

publicclassHttpEncodingAutoConfiguration{


? ? //他已經和SpringBoot的配置文件映射了

privatefinalHttpEncodingPropertiesproperties;

?

//只有一個有參構造器的情況下,參數的值就會從容器中拿

publicHttpEncodingAutoConfiguration(HttpEncodingPropertiesproperties) {

this.properties=properties;

?? }

?

@Bean//給容器中添加一個組件,這個組件的某些值需要從properties中獲取

@ConditionalOnMissingBean

publicCharacterEncodingFiltercharacterEncodingFilter() {

CharacterEncodingFilterfilter=newOrderedCharacterEncodingFilter();

filter.setEncoding(this.properties.getCharset().name());

filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.REQUEST));

filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.RESPONSE));

returnfilter;

?? }

根據當前不同的條件判斷,決定這個配置類是否生效;

一旦這個配置類生效,這個配置類就會給容器中添加各種組件,這些組件的屬性是從對應的properties類中獲取的,這些類里的每一個屬性又是和配置文件綁定的;

5)所有在配置文件中能配置的屬性都是在xxxProperties類中封裝著;配置文件能配置什么就可以參照某個功能 對應的屬性類;

@ConfigurationProperties(//從配置文件中獲取指定的值和bean的屬性進行綁定

prefix="spring.http.encoding"

)

publicclassHttpEncodingProperties{

publicstaticfinalCharsetDEFAULT_CHARSET;

精髓:

? 1)、Spring Boot啟動會加載大量的自動配置類;

? 2)、我們看我們需要的功能有沒有Spring Boot默認寫好的自動配置類;

? 3)、我們再來看這個自動配置中到底配置了哪些組件;(只要我們要用的組件有,我們就不需要再來配置了);

? 4)、給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性,我們就可以在配置文件中指定這些屬性的值;

xxxAutoConfiguration:自動配置類;

會給容器中添加組件;

xxxProperties:封裝配置文件中的相關屬性;

舉thymeleaf例子:ctrl+n:

@Configuration

@EnableConfigurationProperties({ThymeleafProperties.class})

@ConditionalOnClass({TemplateMode.class})

@AutoConfigureAfter({WebMvcAutoConfiguration.class,WebFluxAutoConfiguration.class})

publicclassThymeleafAutoConfiguration{

ThymeleafProperties.class:

@ConfigurationProperties(

prefix="spring.thymeleaf"

)

publicclassThymeleafProperties{

privatestaticfinalCharsetDEFAULT_ENCODING;

publicstaticfinalStringDEFAULT_PREFIX="classpath:/templates/";

publicstaticfinalStringDEFAULT_SUFFIX=".html";

privatebooleancheckTemplate=true;

privatebooleancheckTemplateLocation=true;

privateStringprefix="classpath:/templates/";

privateStringsuffix=".html";

privateStringmode="HTML";

privateCharsetencoding;

privatebooleancache;

privateIntegertemplateResolverOrder;

privateString[]viewNames;

privateString[]excludedViewNames;

privatebooleanenableSpringElCompiler;

privatebooleanenabled;

privatefinalThymeleafProperties.Servletservlet;

privatefinalThymeleafProperties.Reactivereactive;

這樣application.properties文件中可以加的配置可以有:

spring.thymeleaf.prefix=classpath:/templates/

spring.thymeleaf.suffi=.html

spring.thymeleaf.checkTemplate=true

2、細節

1、@Conditional派生注解(Spring注解版@Conditional作用)

作用:必須是@Conditional指定的條件成立,才給容器中添加組件,配置里面的內容才能生效;

自動配置類在一定條件下才能生效;

我們可以在配置文件中啟動debug=true屬性來讓控制臺打印自動配置報告;這樣我們就可以方便知道哪些自動配置類生效;

============================

CONDITIONSEVALUATIONREPORT

============================

?

?

Positivematches:(自動配置類啟用的)

-----------------

?

CodecsAutoConfigurationmatched:

-@ConditionalOnClassfoundrequiredclass'org.springframework.http.codec.CodecConfigurer';@ConditionalOnMissingClassdidnotfindunwantedclass(OnClassCondition)

?

Negativematches:(沒用啟用,沒有匹配成功的自動配置類)

-----------------

?

ActiveMQAutoConfiguration:

Didnotmatch:

-@ConditionalOnClassdidnotfindrequiredclasses'javax.jms.ConnectionFactory','org.apache.activemq.ActiveMQConnectionFactory'(OnClassCondition)

?

4、Web開發

2、Spring Boot對靜態資源的映射規則

@ConfigurationProperties(

prefix="spring.resources",

ignoreUnknownFields=false

)

publicclassResourcePropertiesimplementsResourceLoaderAware,InitializingBean{

//可以設置和靜態資源有關的參數、緩存時間等

publicvoidaddResourceHandlers(ResourceHandlerRegistryregistry) {

if(!this.resourceProperties.isAddMappings()) {

logger.debug("Default resource handling disabled");

}else{

IntegercachePeriod=this.resourceProperties.getCachePeriod();

if(!registry.hasMappingForPattern("/webjars/**")) {

this.customizeResourceHandlerRegistration(registry.addResourceHandler(newString[]{"/webjars/**"}).addResourceLocations(newString[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));

? ? ? ? ? ? ?? }

?

StringstaticPathPattern=this.mvcProperties.getStaticPathPattern();

if(!registry.hasMappingForPattern(staticPathPattern)) {

this.customizeResourceHandlerRegistration(registry.addResourceHandler(newString[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));

? ? ? ? ? ? ?? }

?

? ? ? ? ?? }

? ? ?? }

? ? ? ? //配置歡迎頁

? ? ? ? @Bean

? ? ? ? publicWelcomePageHandlerMappingwelcomePageHandlerMapping(

? ? ? ? ? ? ? ? ResourcePropertiesresourceProperties) {

? ? ? ? ? ? returnnewWelcomePageHandlerMapping(resourceProperties.getWelcomePage(),

? ? ? ? ? ? ? ? ? ? this.mvcProperties.getStaticPathPattern());

? ? ? ? }

? ? ? ? //配置喜歡的圖標

? ? ? ? @Configuration

? ? ? ? @ConditionalOnProperty(value="spring.mvc.favicon.enabled",matchIfMissing=true)

? ? ? ? publicstaticclassFaviconConfiguration{

?

? ? ? ? ? ? privatefinalResourcePropertiesresourceProperties;

?

? ? ? ? ? ? publicFaviconConfiguration(ResourcePropertiesresourceProperties) {

? ? ? ? ? ? ? ? this.resourceProperties=resourceProperties;

? ? ? ? ? ? }

?

? ? ? ? ? ? @Bean

? ? ? ? ? ? publicSimpleUrlHandlerMappingfaviconHandlerMapping() {

? ? ? ? ? ? ? ? SimpleUrlHandlerMappingmapping=newSimpleUrlHandlerMapping();

? ? ? ? ? ? ? ? mapping.setOrder(Ordered.HIGHEST_PRECEDENCE+1);

//所有**/favicon.ico

? ? ? ? ? ? ? ? mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",

? ? ? ? ? ? ? ? ? ? ? ? faviconRequestHandler()));

? ? ? ? ? ? ? ? returnmapping;

? ? ? ? ? ? }

?

? ? ? ? ? ? @Bean

? ? ? ? ? ? publicResourceHttpRequestHandlerfaviconRequestHandler() {

? ? ? ? ? ? ? ? ResourceHttpRequestHandlerrequestHandler=newResourceHttpRequestHandler();

? ? ? ? ? ? ? ? requestHandler

? ? ? ? ? ? ? ? ? ? ? ? .setLocations(this.resourceProperties.getFaviconLocations());

? ? ? ? ? ? ? ? returnrequestHandler;

? ? ? ? ? ? }

?

? ? ? ? }

?

? ? }

1)、所有webjars/*都去classpath:/META-INF/resources/webjars/找資源;

webjars:以jar包的形式引入靜態資源;

http://www.webjars.org/

比如引入jquery3.3.1:


? ? ? ?

? ? ? ? ? ? org.webjars

? ? ? ? ? ? jquery

? ? ? ? ? ? 3.3.1-1


http://localhost:8080/webjars/jquery/3.3.1-1/jquery.js? ? 訪問時只要寫webjars下資源的名稱即可:

2)“/”訪問當前項目的任何資源:(靜態資源的文件夾)**

"/":當前項目的根目錄

"classpath:/META-INF/resources/",

"classpath:/resources/",

"classpath:/static/",

"classpath:/public/

localhost:8080/abc-->默認從靜態資源文件夾里找abc資源;

3)、歡迎頁:靜態資源文件下的index.html頁面,被"/"映射;**

localhost:8080/? 找index.html

比如在public文件夾下放index.html:

4)、所有的/favicon.ico都是在靜態資源文件下找;**

比如在resource文件夾下放一個自定義圖標:

3、模板引擎

JSP、Velocity、Freemarker、Thymeleaf;

SpringBoot推薦的Thymeleaf:

語法更簡單、功能更強大;

1、引入Thymeleaf

切換thymeleaf版本

3.0.9.RELEASE



2.3.0

具體參見:

thymeleaf發布:https://github.com/thymeleaf/thymeleaf/releases

thymeleaf layout dialect:https://github.com/ultraq/thymeleaf-layout-dialect/releases

?

org.springframework.boot

spring-boot-starter-thymeleaf

Layout? 2.0.0的版本開始視頻thymeleaf3

2、Thymeleaf使用&語法

@ConfigurationProperties(prefix="spring.thymeleaf")

publicclassThymeleafProperties{

?

? ? privatestaticfinalCharsetDEFAULT_ENCODING=Charset.forName("UTF-8");

?

? ? privatestaticfinalMimeTypeDEFAULT_CONTENT_TYPE=MimeType.valueOf("text/html");

?

? ? publicstaticfinalStringDEFAULT_PREFIX="classpath:/templates/";

?

? ? publicstaticfinalStringDEFAULT_SUFFIX=".html";

//只要我們把html頁面放到classpath:/templates/路徑下,thymeleaf就能自動渲染

只要我們把html頁面放到classpath:/templates/路徑下,thymeleaf就能自動渲染

使用:

1、導入Thymeleaf的名稱空間

2、使用Thymeleaf的使用

Title

success


這是歡迎信息

3、語法規則

1)、th:text:改變當前元素里面的文本內容;

? th:任意html屬性:來替換原生屬性的值;參考官方pdf文檔第10章(Attribute Precedence:屬性優先級)

2)、表達式?

Simple expressions:(表達式語法)

Variable Expressions: ${...}:獲取變量值:OGNL

? ? 1)、獲取對象的屬性,調用方法

? ? 2)、使用內置的基本對象

? ? #ctx : the context object.

?? #vars: the context variables.

?? #locale : the context locale.

?? #request : (only in Web Contexts) the HttpServletRequest object.

?? #response : (only in Web Contexts) the HttpServletResponse object.

?? #session : (only in Web Contexts) the HttpSession object.

?? #servletContext : (only in Web Contexts) the ServletContext object.


?? ${session.foo}

?? 3)、內置的一些工具對象

?? #execInfo : information about the template being processed.

#messages : methods for obtaining externalized messages inside variables expressions, in the? same way as they would be obtained using #{…} syntax.

?? #uris : methods for escaping parts of URLs/URIs

?? #conversions : methods for executing the configured conversion service (if any).

?? #dates : methods for java.util.Date objects: formatting, component extraction, etc.

?? #calendars : analogous to #dates , but for java.util.Calendar objects.

?? #numbers : methods for formatting numeric objects.

?? #strings : methods for String objects: contains, startsWith, prepending/appending, etc.

?? #objects : methods for objects in general.

?? #bools : methods for boolean evaluation.

?? #arrays : methods for arrays.

?? #lists : methods for lists.

?? #sets : methods for sets.

?? #maps : methods for maps.

?? #aggregates : methods for creating aggregates on arrays or collections.

#ids : methods for dealing with id attributes that might be repeated (for example, as a? ? result of an iteration).

Selection Variable Expressions: *{...} :選擇表達式,和${}功能上是一樣的

? ? 補充:配合th:object=${session.user};

? ?

? ? ??

Name: Sebastian.

? ? ??

Surname: Pepper.

? ? ??

Nationality: Saturn.


? ? 等價于:

? ?

? ? ??

Name: Sebastian.

? ? ??

Surname: Pepper.

? ? ??

Nationality: Saturn.


Message Expressions: #{...}:獲取國際化內容

Link URL Expressions: @{...}:獲取URL:

? ? @{/order/process(execId=${execId},execType='FAST')}

Fragment Expressions: ~{...}:片段引用的表達式

? ?

...

Literals(字面量)

?? Text literals: 'one text' , 'Another one!' ,…

?? Number literals: 0 , 34 , 3.0 , 12.3 ,…

?? Boolean literals: true , false

?? Null literal: null

? ? Literal tokens: one , sometext , main ,…

Text operations:(文本操作)

?? String concatenation: +

?? Literal substitutions: |The name is ${name}|

Arithmetic operations:(數學運算)

?? Binary operators: + , - , * , / , %

?? Minus sign (unary operator): -

Boolean operations:(布爾運算)

?? Binary operators: and , or

?? Boolean negation (unary operator): ! , not

Comparisons and equality:(比較運算)

?? Comparators: > , < , >= , <= ( gt , lt , ge , le )

?? Equality operators: == , != ( eq , ne )

Conditional operators:(條件運算,包括三元運算符)

?? If-then: (if) ? (then)

?? If-then-else: (if) ? (then) : (else)

?? Default: (value) ?: (defaultvalue)

Special tokens:

Page 17 of 104No-Operation:

4、SpringMVC自動配置

https://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications

27.1.1 Spring MVC Auto-configuration

SpringBoot自動配置好了SpringMVC

以下是SpringBoot對SpringMVC的默認配置:

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

The auto-configuration adds the following features on top of Spring’s defaults:

Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

自動配置了ViewResolver(視圖解析器:根據返回值得到視圖對象(View),視圖對象決定如何渲染 (轉發?重定向?))

ContentNegotiatingViewResolver :組合所有的視圖解析器;

如何定制:我們可以自己給容器中添加一個視圖解析器;自動將其組合進來;

@Bean

? ? publicViewResolvermyViewResolver(){

? ? ? ? returnnewmyViewResolver();

? ? }

?

? ? privatestaticclassmyViewResolverimplementsViewResolver{

?

? ? ? ? @Override

? ? ? ? publicViewresolveViewName(StringviewName,Localelocale)throwsException{

? ? ? ? ? ? returnnull;

? ? ? ? }

? ? }

在DispatcherServlet的doDispatch方法打斷點,調試:

隨便訪問一個地址:http://localhost:8080/success

通過控制臺的variable可以看到我們自己寫的視圖解析器添加到viewResolver了:

Support for serving static resources, including support for WebJars (covered later in this document)).

靜態資源文件夾路徑、webjars

Automatic registration of Converter, GenericConverter, and Formatter beans.

Converter:轉換器: public String sayHello(User user):類型轉換使用;

Formatter:格式化器:2017-12-01===Date;

@Bean

@ConditionalOnProperty(prefix="spring.mvc",name="date-format")//在文件中配置日期格式化規則

publicFormatterdateFormatter() {

returnnewDateFormatter(this.mvcProperties.getDateFormat());//日期格式化組件

}

自己添加的格式化器轉換器:我們只要放入容器中即可;

?

Support for HttpMessageConverters (covered later in this document).

HttpMessageConverters:SpringMVC用來轉換Http請求和響應的;User---json;

HttpMessageConverters:是從容器中確定的;獲取所有的HttpMessageConverters;自己給容器中添加HttpMessageConverters,只需要注冊到容器中即可(@Bean,@Componet);

importorg.springframework.boot.autoconfigure.web.HttpMessageConverters;

importorg.springframework.context.annotation.*;

importorg.springframework.http.converter.*;

?

@Configuration

publicclassMyConfiguration{

?

? ? @Bean

? ? publicHttpMessageConverterscustomConverters() {

? ? ? ? HttpMessageConverteradditional=...

? ? ? ? HttpMessageConverteranother=...

? ? ? ? returnnewHttpMessageConverters(additional,another);

? ? }

?

}

Automatic registration of MessageCodesResolver (covered later in this document).定義錯誤代碼生成規則

Static index.html support.靜態首頁訪問

Custom Favicon support (covered later in this document). favicon.ico標簽圖標

Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

我們可以配置ConfigurableWebBindingInitializer來替換默認的;(要添加到容器中)

初始化WebDataBinder

請求數據綁定到javabean中

org.springframework.boot.autoconfigure.web:web所有的自動配置場景;

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

5、如何修改Spring Boot的默認配置

模式:

? 1)SpringBoot在配置很多組件的時候,先看容器中有無用戶配置的組件(@Bean、@Component),如果有就用用戶配置的,如果沒有,才自動配置;如果有些組件可以有多個(ViewResolver)將用戶配置的和自己默認的組合起來;

2)、擴展SpringMVC

? ?

? ?

編寫一個配置類(@Configuration),是WebMvcConfigurer 類型的,不能標注EnableWebMvc注解。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容