日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

一文入门 Spring Boot

發布時間:2024/3/13 javascript 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文入门 Spring Boot 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • No.1 創建 Spring Boot 的三種方式
      • 1、在線創建
      • 2、使用開發工具創建
      • 3、Maven 創建
    • No.2 純 Java 搭建 SSM 環境
      • 1、創建工程
      • 2、添加 Spring 配置
      • 3、添加 Spring MVC 配置
      • 4、靜態資源過濾
      • 5、視圖解析器
      • 6、路徑映射
      • 7、JSON 配置
      • 8、配置 web.xml
    • No.3 深入了解 parent
      • 1、基本功能
      • 2、源碼分析
    • No.4 application.properties
      • 1、位置問題
      • 2、文件名問題
      • 3、普通的屬性注入
      • 4、類型安全的屬性注入
    • No.5 靜態資源到底要放到哪里
      • 1、SSM 中的配置
      • 2、Spring Boot 中的配置
      • 3、Spring Boot 中的靜態資源到底是怎樣配置的呢
      • 4、自定義配置
        • 4.1 application.properties
        • 4.2 Java 代碼定義
    • No.6 Spring Boot 整合 Thymeleaf
      • 1、Thymeleaf 簡介
      • 2、整合
        • 2.1 創建項目
        • 2.2 創建 Controller
        • 2.3 創建 Thymeleaf
      • 3、手動渲染
    • No. 7 異常處理的套路
      • 1、統一異常處理
      • 2、靜態異常頁面
      • 3、動態異常頁面
      • 4、自定義異常數據
      • 5、自定義異常視圖
      • 6、全局異常處理
        • 6.1 全局異常處理
        • 6.2 全局數據綁定
        • 6.3 全局數據預處理
    • No. 8 通過 CORS 跨域問題
      • 1、同源策略
      • 2、實踐
      • 3、存在的問題
    • No.9 Spring Boot 整合 Redis
      • 1、Spring Data Redis
      • 2、Spring Cache
    • No.10 Session 解決方案
    • No.11 Spring Boot 整合 Ehcache
    • No.12 Spring Boot 定義系統啟動任務
      • 1、CommandLineRunner
      • 2、ApplicationRunner
    • No.13 Spring Boot 整合 MyBatis
    • No.14 Spring Boot 多數據源配置之 JdbcTemplate
    • No.15 Spring Boot 整合 MyBatis 多數據源

No.1 創建 Spring Boot 的三種方式

1、在線創建

這是官方提供的一個創建方式,實際上,如果我們使用開發工具去創建 Spring Boot 項目的話(即第二種方案),也是從這個網站上創建的,只不過這個過程開發工具幫助我們完成了,我們只需要在開發工具中進行簡單的配置即可

首先打開 https://start.spring.io 這個網站,如下:

這里要配置的按順序分別如下:

  • 項目構建工具是 Maven 還是 Gradle ?Gradle 在 Java 后端中使用的還是比較少,Gradle 在 Android 中使用較多,Java 后端,目前來看還是 Maven 為主,因此這里選擇第一項。
  • 開發語言,這個當然是選擇 Java 了
  • Spring Boot 版本,可以看到,目前最新的穩定版是 2.1.6 ,這里我們就是用最新穩定版。
  • 既然是 Maven 工程,當然要有項目坐標,項目描述等信息了,另外這里還讓輸入了包名,因為創建成功后會自動創建啟動類。
  • Packing 表示項目要打包成 jar 包還是 war 包,Spring Boot 的一大優勢就是內嵌了 Servlet 容器,打成 jar 包后可以直接運行,所以這里建議打包成 jar 包,當然,開發者根據實際情況也可以選擇 war 包。
  • 然后選選擇構建的 JDK 版本。
  • 最后是選擇所需要的依賴,輸入關鍵字如 web ,會有相關的提示,這里我就先加入 web 依賴。

所有的事情全部完成后,點擊最下面的 GenerateProject 按鈕,或者點擊 Alt+Enter 按鍵,此時會自動下載項目,將下載下來的項目解壓,然后用 IntelliJ IDEA 或者 Eclipse 打開即可進行開發。

2、使用開發工具創建

這里以 IntelliJ IDEA 為例,需要注意的是,IntelliJ IDEA 只有 ultimate 版才有直接創建 Spring Boot 項目的功能,社區版是沒有此項功能的

3、Maven 創建

首先創建一個普通的 Maven 項目,以 IntelliJ IDEA 為例,創建步驟如下:

創建完成后,在 pom.xml 加入如下依賴:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version><relativePath/> </parent> <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> </dependencies>

添加成功后,再在 java 目錄下創建包,包中創建一個名為 App 的啟動類,如下:

@SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}}

No.2 純 Java 搭建 SSM 環境

1、創建工程

創建一個普通的 Maven 工程,并添加 Spring MVC 依賴,同時還需要使用到 Servlet,所以還要引入 Servlet 依賴,最終 pom.xml 如下:

<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.kernel</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.6.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency></dependencies> </project>

2、添加 Spring 配置

工程創建成功后,首先添加 Spring 配置文件,如下:

@Configuration @ComponentScan(basePackages = "com.kernel", useDefaultFilters = true, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}) public class SpringConfig { }
  • @Configuration 表示這個類是一個配置類
  • @ComponentScan 表示配置掃包范圍
    • useDefaultFilters 是否使用默認的過濾器
    • excludeFilters 表示去掉的注解
    • includeFilters 表示包含的注解

3、添加 Spring MVC 配置

@Configuration @ComponentScan(basePackages = "com.kernel",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}) public class SpringMVCConfig { }

4、靜態資源過濾

在 Java 配置的 SSM 環境中,如果要配置靜態資源過濾,需要讓 Spring MVC 的配置繼承 WebMvcConfigurationSupport ,進而重寫 WebMvcConfigurationSupport 中的 addResourceHandlers 方法,如下:

@Configuration @ComponentScan(basePackages = "com.kernel",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}) public class SpringMVCConfig extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/js/**").addResourceLocations("classpath:/");} }

5、視圖解析器

如果開發者使用了 jsp,需要引入 jsp 的依賴,如下:

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.kernel</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.6.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.49</version></dependency></dependencies> </project>

在 Java 配置的 SSM 環境中,如果要配置視圖解析器,需要讓 Spring MVC 的配置繼承 WebMvcConfigurationSupport ,進而重寫 WebMvcConfigurationSupport 中的 configureViewResolvers 方法,如下:

@Configuration @ComponentScan(basePackages = "com.kernel",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}) public class SpringMVCConfig extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/js/**").addResourceLocations("classpath:/");}@Overrideprotected void configureViewResolvers(ViewResolverRegistry registry) {registry.jsp("/jsp/", ".jsp");} }

6、路徑映射

在 Java 配置的 SSM 環境中,如果要配置路徑映射,需要讓 Spring MVC 的配置繼承 WebMvcConfigurationSupport ,進而重寫 WebMvcConfigurationSupport 中的 addViewControllers 方法,如下:

@Configuration @ComponentScan(basePackages = "com.kernel",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}) public class SpringMVCConfig extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/js/**").addResourceLocations("classpath:/");}@Overrideprotected void configureViewResolvers(ViewResolverRegistry registry) {registry.jsp("/jsp/", ".jsp");}@Overrideprotected void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/index").setViewName("/hello");} }

7、JSON 配置

Spring MVC 可以接收 JSON 參數,也可以發送 JSON 參數,這一切依賴于 HttpMessageConverter

HttpMessageConverter 可以將 JSON 轉換成字符串,也可以將字符串轉換成 JSON

所有的 JSON 庫要在 Spring MVC 自動接收和發送 JSON,都必須提供相關的 HttpMessageConverter

如果開發者使用了 fastjson,需要引入 fastjson 的依賴,如下:

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.kernel</groupId><artifactId>ssm</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.6.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.49</version></dependency></dependencies> </project>

在 Java 配置的 SSM 環境中,需要顯式配置 HttpMessageConverter,需要讓 Spring MVC 的配置繼承 WebMvcConfigurationSupport ,重寫 WebMvcConfigurationSupport 中的 configureMessageConverters 方法,如下:

@Configuration @ComponentScan(basePackages = "com.kernel",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}) public class SpringMVCConfig extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/js/**").addResourceLocations("classpath:/");}@Overrideprotected void configureViewResolvers(ViewResolverRegistry registry) {registry.jsp("/jsp/", ".jsp");}@Overrideprotected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();converter.setDefaultCharset(Charset.forName("UTF-8"));FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setCharset(Charset.forName("UTF-8"));converter.setFastJsonConfig(fastJsonConfig);converters.add(converter);} }

8、配置 web.xml

此時,我們并沒有 web.xml 文件,這時,我們可以使用 Java 代碼去代替 web.xml 文件,這里會用到 WebApplicationInitializer,具體定義如下:

public class WebInit implements WebApplicationInitializer {public void onStartup(ServletContext servletContext) throws ServletException {//首先來加載 SpringMVC 的配置文件AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringMVCConfig.class);// 添加 DispatcherServletServletRegistration.Dynamic springmvc = servletContext.addServlet("springmvc", new DispatcherServlet(ctx));// 給 DispatcherServlet 添加路徑映射springmvc.addMapping("/");// 給 DispatcherServlet 添加啟動時機springmvc.setLoadOnStartup(1);} }

WebInit 的作用類似于 web.xml,這個類需要實現 WebApplicationInitializer 接口,并實現接口中的方法,當項目啟動時,onStartup 方法會被自動執行,我們可以在這個方法中做一些項目初始化操作

No.3 深入了解 parent

上面介紹了三種創建 Spring Boot 的方式,但是無論是哪種方式,pom.xml 中必然會引入一個依賴:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version><relativePath/> </parent>

1、基本功能

當我們創建一個 Spring Boot 工程時,可以繼承一個 spring-boot-starter-parent,也可以不繼承它

  • 定義了 Java 編譯版本為 1.8
  • 使用 UTF-8 格式編碼
  • 繼承自 spring-boot-dependencies,這個里面定義了依賴的版本,也正是因為繼承了這個依賴,所以我們在寫依賴時不需要寫版本號
  • 執行打包操作的配置
  • 自動化的資源過濾
  • 自動化的插件配置
  • 針對 application.properties 和 application.yml 的資源過濾,包括通過 profile 定義的不同環境的配置文件

2、源碼分析

我們可以看到,它繼承自 spring-boot-dependencies ,這里保存了基本的依賴信息,另外我們也可以看到項目的編碼格式,JDK 的版本等信息,當然也有我們前面提到的數據過濾信息。最后,我們再根據它的 parent 中指定的 spring-boot-dependencies 位置,來看看 spring-boot-dependencies 中的定義:

在這里我們發現里面放置了版本號信息以及 dependencyManagement 節點

No.4 application.properties

1、位置問題

當我們創建一個 Spring Boot 項目的時候,默認的 resource 目錄下會生成一個 application.properties 文件,改文件存放項目的配置信息,但是這個文件并非唯一的配置文件,在 Spring Boot 項目中,一共有四個地方可以存放application.properties,按優先級排列,如下:

  • 當前項目根目錄下的 config 目錄下
  • 當前項目的根目錄下
  • resources 目錄下的 config 目錄下
  • resources 目錄下

這四個目錄是默認位置,也就是說默認情況下 Spring Boot 啟動時會從這四個位置查找配置文件,我們也可以在項目啟動前自定義配置文件位置,使用 spring.config.loaction 來指定目錄位置

如下項目已經打包成 jar,在啟動命令中加入位置參數即可:

java -jar properties-0.0.1-SNAPSHOT.jar --spring.config.location=classpath:/dir/

2、文件名問題

對于 application.proerties,文件名并非一定要叫 application,但是項目默認加載的文件名是 application,如果我們的配置文件名字不叫 application,也是可以的,但是要通過 spring.config.name 配置

如下項目已經打包成 jar,在啟動命令中加入位置參數即可:

java -jar properties-0.0.1-SNAPSHOT.jar --spring.config.name=test

3、普通的屬性注入

由于 Spring Boot 源自 Spring ,所以 Spring 中存在的屬性注入,在 Spring Boot 中一樣也存在。由于 Spring Boot 中,默認會自動加載 application.properties 文件,所以簡單的屬性注入可以直接在這個配置文件中寫

@Component public class Book {@Value("${book.id}")private Long id;@Value("${book.name}")private String name;@Value("${book.author}")private String author; }

然后在 application.properties 文件中定義屬性

book.name=三國演義 book.author=羅貫中 book.id=1

一般來說,我們在 application.properties 文件中主要存放系統配置,這種自定義配置不建議放在該文件中,可以自定義 properties 文件來存在自定義配置

在 resource 目錄下, 創建 book.properties 文件

在 Java 配置中,可以通過 @PropertySource 來引入配置:

@Component @PropertySource("classpath:book.properties") public class Book {@Value("${book.id}")private Long id;@Value("${book.name}")private String name;@Value("${book.author}")private String author; }

4、類型安全的屬性注入

Spring Boot 引入了類型安全的屬性注入,如果采用 Spring 中的配置方式,當配置的屬性非常多的時候,工作量就很大了,而且容易出錯

使用類型安全的屬性注入,可以有效的解決這個問題

@Component @PropertySource("classpath:book.properties") @ConfigurationProperties(prefix = "book") public class Book {private Long id;private String name;private String author; }

No.5 靜態資源到底要放到哪里

1、SSM 中的配置

在 Java 代碼中配置,如果在Java代碼中配置的話,我們只需要自定義一個類,繼承 WebMvcConfigurationSupport 并重寫 addResourceHandlers 方法即可:

@Configuration @ComponentScan(basePackages = "com.kernel.ssm")public class SpringMVCConfig extends WebMvcConfigurationSupport {@Override protected void addResourceHandlers (ResourceHandlerRegistry registry){registry.addResourceHandler("/**").addResourceLocations("/");} }

2、Spring Boot 中的配置

在 Spring Boot 中,默認情況下,一共有5個位置可以存放靜態資源,按優先級分別是:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/
  • /

前四個目錄對應了 resources 目錄下的不同目錄,第五個其實就是 webapp

3、Spring Boot 中的靜態資源到底是怎樣配置的呢

首先我們在 WebMvcAutoConfiguration 類中看到了 SpringMVC 自動化配置的相關的內容,找到了靜態資源攔截的配置,如下:

這里靜態資源的配置和前面的 SSM 配置非常相似,其中,this.mvcProperties.getStaticPathPattern() 方法對應的值是"/**",this.resourceProperties.getStaticLocations()方法返回了四個位置,分別是:“classpath:/META-INF/resources/”, “classpath:/resources/”,“classpath:/static/”, “classpath:/public/”,然后在getResourceLocations方法中,又添加了“/”,因此這里返回值一共有5個,這就是為什么靜態資源請求路徑中不需要 /static,因為在路徑映射中已經自動的添加上了 /static 了

4、自定義配置

當然了,這個是系統默認配置,如果我們不想講靜態資源放到以上五個目錄中,也可以自定義靜態資源位置和映射,自定義的方式也有兩種,可以通過 application.properties 來定義,也可以在 Java 代碼中來定義

4.1 application.properties

spring.resources.static-locations=classpath:/ spring.mvc.static-path-pattern=/**

第一行配置表示定義資源位置,第二行配置表示定義請求 URL 規則,上面標示可以將靜態資源存放到 resources 目錄下的任意目錄,我們訪問的時候當然也要寫完整路徑

4.2 Java 代碼定義

@Configuration public class WebMVCConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers (ResourceHandlerRegistry registry) {registry.addResourceHandler("/**").addResourceLocations("classpath:/aaa/");} }

No.6 Spring Boot 整合 Thymeleaf

1、Thymeleaf 簡介

Thymeleaf 是新一代 Java 模板引擎,它類似于 Velocity、FreeMarker 等傳統 Java 模板引擎,但是與傳統 Java 模板引擎不同的是,Thymeleaf 支持 HTML 原型。

它既可以讓前端工程師在瀏覽器中直接打開查看樣式,也可以讓后端工程師結合真實數據查看顯示效果,同時,Spring Boot 提供了 Thymeleaf 自動化配置解決方案,因此在 Spring Boot 中使用 Thymeleaf 非常方便。

事實上, Thymeleaf 除了展示基本的 HTML ,進行頁面渲染之外,也可以作為一個 HTML 片段進行渲染,例如我們在做郵件發送時,可以使用 Thymeleaf 作為郵件發送模板。

另外,由于 Thymeleaf 模板后綴為 .html,可以直接被瀏覽器打開,因此,預覽時非常方便。

2、整合

2.1 創建項目

Spring Boot 中整合 Thymeleaf 非常容易,只需要創建項目時添加 Thymeleaf 即可

當然,Thymeleaf 不僅僅能在 Spring Boot 中使用,也可以使用在其他地方,只不過 Spring Boot 針對 Thymeleaf 提供了一整套的自動化配置方案,這一套配置類的屬性在 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties 中,部分源碼如下:

@ConfigurationProperties(prefix = "spring.thymeleaf")public class ThymeleafProperties {private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;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 = DEFAULT_PREFIX;private String suffix = DEFAULT_SUFFIX;private String mode = "HTML";private Charset encoding = DEFAULT_ENCODING;private boolean cache = true; }

首先通過 @ConfigurationProperties 注解,將 application.properties 中前綴為 spring.thymeleaf 的屬性和 ThymeleafProperties 綁定

  • 前三個static 配置了默認編碼、視圖解析器的前綴和后綴
  • 從前三行來看,thymeleaf 模板的默認位置在 classpath:/templates/ 目錄,默認后綴是 .html
  • 這些配置是默認配置,如需改變,使用 spring.thymeleaf 為前綴

Spring Boot 為 Thymeleaf 提供的自動化配置類,則是org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,部分源碼如下:

@Configuration @EnableConfigurationProperties(ThymeleafProperties.class) @ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class }) @AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class }) public class ThymeleafAutoConfiguration { }

可以看到,首先導入 ThymeleafProperties,然后 @ConditionalOnClass 注解表示當前系統中存在 TemplateMode、SpringTemplateEngine 類時,此自動化配置類才生效,即只有引入了 thymeleaf 依賴,此配置類生效

2.2 創建 Controller

@Controller public class IndexController {@GetMapping("/index")public String index(Model model) {List<User> users = new ArrayList<>();for (int i = 0; i < 10; i++) {User u = new User();u.setId((long) i);u.setName("kernel:" + i);u.setAddress("深圳:" + i);users.add(u);}model.addAttribute("users", users);model.addAttribute("username", "李四");return "index";} }

2.3 創建 Thymeleaf

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> <table border="1"><tr><td>編號</td><td>用戶名</td><td>地址</td></tr><tr th:each="user : ${users}"><td th:text="${user.id}"></td><td th:text="${user.name}"></td><td th:text="${user.address}"></td></tr> </table> </body> </html>

3、手動渲染

前面我們說的是返回一個 Thymeleaf 模板,我們也可以手動渲染 Thymeleaf 模板,這個一般在郵件發送時候有用,例如我在 resources/templates 目錄下新建一個郵件模板,如下:

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"> <title>Title</title></head><body><p>hello 歡迎 <span th:text="${username}"></span>加入 XXX 集團,您的入職信息如下:</p><table border="1"><tr><td>職位</td><td th:text="${position}"></td></tr><tr> <td>薪水</td> <td th:text="${salary}"></td></tr></table><img src="http://www.javaboy.org/images/sb/javaboy.jpg" alt=""></body> </html>

我們要將這個 HTML 模板渲染成一個 String 字符串,再把這個字符串通過郵件發送出去,那么如何手動渲染呢?

@Autowired TemplateEngine templateEngine;@Test public void fun() throws MessagingException {Context context = new Context();context.setVariable("username", "javaboy");context.setVariable("position", "Java工程師");context.setVariable("salary", 99999);String mail = templateEngine.process("mail", context); }
  • 渲染時,我們需要首先注入一個 TemplateEngine 對象,這個對象就是在 Thymeleaf 的自動化配置類中配置的
  • 然后構造一個 Context 對象用來存放變量
  • 調用 process 方法進行渲染,該方法的返回值就是渲染后的 HTML 字符串,然后我們將這個字符串發送出去

No. 7 異常處理的套路

1、統一異常處理

在 Spring Boot 中,異常統一處理,可以使用 @ControllerAdvice 來處理,也可以使用自定義異常處理方案

默認情況下,Spring Boot 的異常頁面是這樣的:

從這個異常中,可以看到,之所以出現這個頁面,是因為開發者沒有提供 /error 對應的頁面,Spring Boot 本身在處理異常時,當所有條件都不滿足時,才會去找 /error 路徑

在 Spring Boot 中,自定義 error 頁面,主要可以分為靜態頁面和動態頁面

2、靜態異常頁面

自定義靜態異常頁面又分為兩種,一種是用 HTTP 響應碼命令,例如 404.html、405.html、500.html,還有一種直接就是以 4xx.html、5xx.html 命名,包括 400-499 和 500-599 的所有異常

默認是在 classpath:/static/error/ 目錄下定義相關頁面

此時,啟動項目,如果發生 500 錯誤,項目中存在 5xx.html 和 500.html,會優先展示 500.html

3、動態異常頁面

動態的異常頁面定義方式和靜態的基本 一致,可以采用的頁面模板有 jsp、freemarker、thymeleaf。動態異常頁面,也支持 404.html 或者 4xx.html ,但是一般來說,由于動態異常頁面可以直接展示異常詳細信息,所以就沒有必要挨個枚舉錯誤了 ,直接定義 4xx.html 或者 5xx.html 即可

動態頁面模板,不需要開發者去定義控制器,直接定義異常頁面就可以,Spring Boot 自帶的異常處理器會自動查找異常頁面

4、自定義異常數據

默認情況下,在Spring Boot 中,所有的異常數據定義在 org.springframework.boot.web.reactive.error.DefaultErrorAttributes 類中,具體定義在 getErrorAttributes 方法中 :

@Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {Map<String, Object> errorAttributes = new LinkedHashMap<>();errorAttributes.put("timestamp", new Date());addStatus(errorAttributes, webRequest);addErrorDetails(errorAttributes, webRequest, includeStackTrace);addPath(errorAttributes, webRequest);return errorAttributes; }

DefaultErrorAttributes 類本身則是在org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration 異常自動配置類中定義的,如果開發者沒有自己提供一個 ErrorAttributes 的實例的話,那么 Spring Boot 將自動提供一個ErrorAttributes 的實例,也就是 DefaultErrorAttributes

基于此 ,開發者自定義 ErrorAttributes 有兩種方式 :

  • 直接實現 ErrorAttributes 接口
  • 繼承 DefaultErrorAttributes(推薦),因為 DefaultErrorAttributes 中對異常數據的處理已經完成,開發者可以直接使用
  • 具體定義如下:

    @Component public class MyErrorAttribute extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);if ((Integer) map.get("status") == 500) {map.put("message", "服務器內部錯誤!");}return map;} }

    5、自定義異常視圖

    默認的異常視圖加載邏輯在 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController 類的 errorHtml 方法中,這個方法用來返回異常頁面+數據,還有另外一個 error 方法,這個方法用來返回異常數據(如果是 ajax 請求,則該方法會被觸發)

    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status = getStatus(request);Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));response.setStatus(status.value());ModelAndView modelAndView = resolveErrorView(request, response, status, model);return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); }

    在該方法中 ,首先會通過 getErrorAttributes 方法去獲取異常數據,然后調用 resolveErrorView 去創建一個 ModelAndView ,如果這里創建失敗,那么用戶將會看到默認的錯誤提示頁面

    正常情況下, resolveErrorView 方法會來到 DefaultErrorViewResolver 類的 resolveErrorView 方法中:

    protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status,Map<String, Object> model) {for (ErrorViewResolver resolver : this.errorViewResolvers) {ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);if (modelAndView != null) {return modelAndView;}}return null; }

    在這里,首先以異常響應碼作為視圖名分別去查找動態頁面和靜態頁面,如果沒有查找到,則再以 4xx 或者 5xx 作為視圖名再去分別查找動態或者靜態頁面

    要自定義異常視圖解析,也很容易 ,由于 DefaultErrorViewResolver 是在 ErrorMvcAutoConfiguration 類中提供的實例,即開發者沒有提供相關實例時,會使用默認的 DefaultErrorViewResolver ,開發者提供了自己的 ErrorViewResolver 實例后,默認的配置就會失效,因此,自定義異常視圖,只需要提供 一個 ErrorViewResolver 的實例即可:

    @Component public class MyErrorViewResolver extends DefaultErrorViewResolver {public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) {super(applicationContext, resourceProperties);}@Overridepublic ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {ModelAndView modelAndView = new ModelAndView("test/5xx",model);return modelAndView;} }

    到此,異常視圖就自定義成功了

    6、全局異常處理

    @ControllerAdvice,這是一個增強的 Controller,可以實現三個功能:

    • 全局異常處理
    • 全局數據綁定
    • 全局數據預處理

    6.1 全局異常處理

    使用 @ControllerAdvice 實現全局異常處理,只需要定義類,添加該注解即可定義方式如下:

    @ControllerAdvice public class MyGlobalExceptionHandler {@ExceptionHandler(Exception.class)public ModelAndView customerException(Exception e) {ModelAndView modelAndView = new ModelAndView();modelAndView.addObject("message", e.getMessage());modelAndView.setViewName("error");return modelAndView;} }

    在該類中,可以定義多個方法,不同的方法處理不同的異常,也可以在統一方法處理所有異常

    @ExceptionHandler 注解用來指明異常的處理類型

    6.2 全局數據綁定

    全局數據綁定功能可以用來做一些初始化的數據操作,我們可以將一些公共的數據定義在添加了 @ControllerAdvice 注解的類中,這樣,在每個 Controller 中都能訪問這些數據

    @ControllerAdvice public class MyGlobalExceptionHandler {@ModelAttribute(name = "md")public Map<String, Object> mydata() {HashMap<String, Object> map = new HashMap<>();map.put("age", 99);map.put("gender", "男");return map;} }

    使用 @ModelAttribute 注解標記該方法的返回數據是一個全局數據,默認情況下,這個全局數據的 key 就是返回的變量名,value 就是方法返回值,當然開發者可以通過 @ModelAttribute 注解的 name 屬性去重新指定 key

    定義完成后,任意 Controller 的接口都能獲取到定義的全局數據:

    @RestController public class HelloController {@GetMapping("/hello")public String hello(Model model) {Map<String, Object> map = model.asMap();System.out.println(map);int i = 1 / 0;return "hello";} }

    6.3 全局數據預處理

    考慮我有兩個實體類,Book 和 Author

    此時,如果我定義一個數據添加接口,如下:

    @PostMapping public void addBook(Book book, Author author) {System.out.println(book);System.out.println(author); }

    這個時候,添加操作就是出現問題,因為這兩個實體類都存在一個 name 屬性,所以無法區分,此時,通過全局數據預處理可以解決這個問題

    步驟如下:

    給接口中的變量取別名

    @PostMapping public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {System.out.println(book);System.out.println(author); }

    進行請求數據預處理

    @InitBinder("b") public void b(WebDataBinder binder) {binder.setFieldDefaultPrefix("b."); }@InitBinder("a") public void a(WebDataBinder binder) {binder.setFieldDefaultPrefix("a."); }

    No. 8 通過 CORS 跨域問題

    1、同源策略

    如果兩個頁面的協議,端口(如果有指定)和主機都相同,則兩個頁面具有相同的源,所謂同源是指協議、域名以及端口要相同。

    同源策略是基于安全方面的考慮提出來的,這個策略本身沒問題,但是我們在實際開發中,由于各種原因又經常有跨域的需求,傳統的跨域方案是JSONP,JSONP雖然能解決跨域但是有一個很大的局限性,那就是只支持GET請求,不支持其他類型的請求,而今天我們說的CORS(跨域源資源共享)(CORS,Cross-origin resource sharing)是一個W3C標準,它是一份瀏覽器技術的規范,提供了Web服務從不同網域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,這是JSONP模式的現代版。

    下表給出了相對http://store.company.com/dir/page.html同源檢測的示例:

    URL結果原因
    http://store.company.com/dir2/other.html成功只有路徑不同
    http://store.company.com/dir/inner/another.html成功只有路徑不同
    https://store.company.com/secure.html失敗不同協議 ( https和http )
    http://store.company.com:81/dir/etc.html失敗不同端口 ( http:// 80是默認的)
    http://news.company.com/dir/other.html失敗不同域名 ( news和store )

    2、實踐

    首先創建兩個 Spring Boot 項目,一個 provider 提供服務,一個 customer 請求服務,第一個端口配置為 8080,第二個配置為 8089,然后在 provider 提供兩個 hello 接口,分別為 get 和 post 方式,如下:

    @RestController public class HelloController {@GetMapping("/hello")public String hello() {return "hello";}@PostMapping("/hello")public String hello2() {return "hello";} }

    在 customer 的 resources/static 創建一個 html 文件,發送簡單的 ajax 請求,如下:

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> </head> <body><div id="app"></div><input type="button" onclick="btnClick()" value="get_button"><input type="button" onclick="btnClick2()" value="post_button"><script>function btnClick() {$.get('http://localhost:8080/hello',function (msg) {$("#app").html(msg);})}function btnClick2() {$.post('http://localhost:8080/hello', function (msg) {$("#app").html(msg);})}</script> </body> </html>

    然后啟動項目,發送請求,觀察控制臺如下:

    Access to XMLHttpRequest at 'http://localhost:8080/hello' from origin 'http://localhost:8089' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    可以看到,由于同源策略的原因,請求無法發送

    在 Spring Boot 中,提供了一個注解,可以解決同源策略的問題

    @RestController public class HelloController {@CrossOrigin(value = "http://127.0.0.1:8089")@GetMapping("/hello")public String hello() {return "hello";}@CrossOrigin(value = "http://127.0.0.1:8089")@PostMapping("/hello")public String hello2() {return "hello";} }

    這個注解表示這兩個接口的接收來自 http://127.0.0.1:8089 地址的請求,配置完成后就可以接收到數據了

    可以看到響應頭中多了一個信息,表示服務端愿意接收來自 http://127.0.0.1:8089 的請求,即瀏覽器不會再限制本次請求的跨域了

    每一個方法上都去加注解未免太麻煩了,在Spring Boot中,還可以通過全局配置一次性解決這個問題,全局配置只需要在配置類中重寫 addCorsMappings方法即可,如下:

    public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://127.0.0.1:8089").allowedMethods("*").allowedHeaders("*");} }

    /** 表示本應用的所有方法都會去處理跨域請求,allowedMethods 表示允許通過的請求數,allowedHeaders 則表示允許的請求頭,經過這樣的配置之后,就不必在每個方法上單獨配置跨域了。

    3、存在的問題

    了解了整個CORS的工作過程之后,我們通過Ajax發送跨域請求,雖然用戶體驗提高了,但是也有潛在的威脅存在,常見的就是CSRF(Cross-site request forgery)跨站請求偽造??缯菊埱髠卧煲脖环Q為one-click attack 或者 session riding,通常縮寫為CSRF或者XSRF,是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法,舉個例子:

    假如一家銀行用以運行轉賬操作的URL地址如下: http://icbc.com/aa?bb=cc,那么,一個惡意攻擊者可以在另一個網站上放置如下代碼: <imgsrc="http://icbc.com/aa?bb=cc">,如果用戶訪問了惡意站點,而她之前剛訪問過銀行不久,登錄信息尚未過期,那么她就會遭受損失。

    基于此,瀏覽器在實際操作中,會對請求進行分類,分為簡單請求,預先請求,帶憑證的請求等,預先請求會首先發送一個options探測請求,和瀏覽器進行協商是否接受請求,默認情況下跨域請求是不需要憑證的,但是服務端可以配置要求客戶端提供憑證,這樣就可以有效避免 CSRF 攻擊

    No.9 Spring Boot 整合 Redis

    使用 Java 操作 Redis 的方案有很多,Jedis 是目前最流行的方式,除了 Jedis 還有很多其他的解決方案,如下:

    在傳統的 SSM 中,需要開發者手動配置 Spring Data Redis,這個配置比較繁瑣,主要配置三個東西:連接池、連接器信息以及 key 和 value 的序列化方案;

    在 Spring Boot 中,默認集成的 Redis 就是 Spring Data Redis,默認的底層連接池采用的是 lettuce;

    Spring Data Redis 針對 Redis 提供了非常方便的操作模板 Redis Template;

    1、Spring Data Redis

    配置 Redis 信息,如下:

    spring:redis:database: 0password:port: 6379host: 192.168.142.128lettuce:pool:min-idle: 5max-idle: 10max-active: 8max-wait: 1time-between-eviction-runs: 1000

    當開發者引入了 Spring Data Redis 的依賴后,并且同時配置了 Redis 信息,此時的配置就會生效,結果就是提供兩個 bean:RedisTemplate 和 StringRedisTemplate,其中 StringRedisTemplate 是 RedisTemplate 的子類,兩者的區別在于 StringRedisTemplate 的 key 和 value 都是 String,而 RedisTemplate 的 key 和 value 都是 Object,這就意味著 StringRedisTemplate 只能操作 String。

    實踐:

    @Autowired RedisTemplate redisTemplate; public void hello() {redisTemplate.setKeySerializer(new StringRedisSerializer());ValueOperations ops = redisTemplate.opsForValue();ops.set("k1", "v1");Object k1 = ops.get("k1");System.out.println(k1); }@Autowired StringRedisTemplate stringRedisTemplate; public void hello2() {ValueOperations ops = stringRedisTemplate.opsForValue();ops.set("k2", "v2");Object k1 = ops.get("k2");System.out.println(k1); }

    2、Spring Cache

    基本配置:

    spring.redis.port=6380 spring.redis.host=192.168.66.128 spring.cache.cache-names=c1

    開啟緩存:

    @EnableCaching @SpringBootApplication public class RedisApplication {public static void main(String[] args) {SpringApplication.run(RedisApplication.class, args);} }

    完成這些配置后,Spring Boot 會自動幫我們在后臺配置一個 RedisCacheManager 的 bean,這個 bean 間接實現了 Spring 的 Cache 接口,有了這個 bean,我們就可以直接使用 Spring 中的緩存注解和接口,而緩存數據會直接被寫入到 Redis 中

    核心注解:

    @CacheConfig 該注解標注在類上,用來描述該類所有方法使用的緩存名稱

    @Cacheable 這個注解一般標注在查詢方法上,將返回值緩存起來,默認情況下,緩存的 key 就是方法的參數,緩存的 value 就是方法的返回值

    當有多個參數時,默認以多個參數 [var1,var2,…] 的形式作為 key,如果只需要某一個參數作為 key,則需要在該注解中指定,如果對key有復雜的要求,可以自定義keyGenerator。當然,Spring Cache中提供了root對象,可以在不定義keyGenerator的情況下實現一些復雜的效果:

    @CachePut 這個注解一般標注在更新方法上,當數據庫的數據更新后,緩存中的數據也跟著更新,使用該注解,將方法的返回值更新到緩存中去

    @CacheEvict 這個注解一般標注在刪除方法上,當數據庫的數據刪除后,相關的緩存數據也要刪除,使用該數據,將按照條件刪除緩存中的數據

    No.10 Session 解決方案

    在這樣的一個架構中,會出現一些但服務架構不存在的問題,那就是客戶端發起一個請求,被 Nginx 轉發到 Tomcat A 上,然后 Tomcat A 往 session 中寫入了一份數據,下次來了一個請求,被 Nginx 轉發到 Tomcat B 上,此時在去 session 中獲取數據,發現 session 是空的,這個問題的解決方案就是將 Tomcat 和 Redis 打通。

    所有的 Tomcat 向 session 中寫數據都向 redis 中寫,從 session 中讀數據都從 redis 里面讀,這樣,不同的服務就可以共享同一 session 了。

    Spring Boot 提供的了一個簡化的方案就是使用 Spring Session 來實現這一功能,Spring Session 就是使用 Spring 中的代理過濾器,將所有的 Session 操作攔截下來,自動的將數據 同步到 Redis 中,或者自動的從 Redis 中讀取數據。

    對于開發者來說,所有關于 Session 同步的操作都是透明的,開發者使用 Spring Session,一旦配置完成后,具體的用法就像使用一個普通的 Session 一樣。

    配置 Redis

    spring:redis:database: 0password:port: 6379host: 192.168.142.128lettuce:pool:min-idle: 5max-idle: 10max-active: 8max-wait: 1time-between-eviction-runs: 1000cache:cache-names: c1server:port: 8080

    實踐

    @Value("${server.port}") Integer port; @GetMapping("/set") public String set(HttpSession session) {session.setAttribute("user", "kernel");return String.valueOf(port); }@GetMapping("/get") public String get(HttpSession session) {return session.getAttribute("user") + ":" + port; }

    修改 nginx.conf

    upstream kernel.org{server 127.0.0.1:8081 weight=1;server 127.0.0.1:8082 weight=2; } server {listen 80;server_name localhost;index index.html index.htm index.php;root /www/server/phpmyadmin;#error_page 404 /404.html;include enable-php.conf;location / {proxy_pass http://kernel.org;proxy_redirect default;} }

    在這段配置中:

    • upstream 表示配置上游服務器
    • javaboy.org 表示服務器集群的名字,這個可以隨意取名字
    • upstream 里邊配置的是一個個的單獨服務
    • weight 表示服務的權重,意味者將有多少比例的請求從 Nginx 上轉發到該服務上
    • location 中的 proxy_pass 表示請求轉發的地址, / 表示攔截到所有的請求,轉發轉發到剛剛配置好的服務集群中
    • proxy_redirect 表示設置當發生重定向請求時,nginx 自動修正響應頭數據(默認是 Tomcat 返回重定向,此時重定向的地址是 Tomcat 的地址,我們需要將之修改使之成為 Nginx 的地址)。

    配置完成后,將項目打包上傳到 Linux 并分別運行:

    java -jar redis-0.0.1-SNAPSHOT.jar --server.port=8081 & java -jar redis-0.0.1-SNAPSHOT.jar --server.port=8081 &

    訪問 192.168.142.128/set 表示向 session 中保存數據,這個請求首先會到達 Nginx 上,再由 Nginx 轉發給某一個實例

    No.11 Spring Boot 整合 Ehcache

    引入 Ehcache 依賴

    添加 Ehcache 配置

    <ehcache><diskStore path="java.io.tmpdir/springboot-sample"/><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="false"diskPersistent="false"diskExpiryThreadIntervalSeconds="120"/><cache name="user"maxElementsInMemory="10000"eternal="true"overflowToDisk="true"diskPersistent="true"diskExpiryThreadIntervalSeconds="600"/> </ehcache>

    配置含義:

    • name:緩存名稱
    • maxElementsInMemory:緩存最大個數
    • eternal:對象是否永久有效,一但設置了,timeout 將不起作用
    • timeToIdleSeconds:設置對象在失效前的允許閑置時間
    • timeToLiveSeconds:設置對象在失效前允許存活時間
    • overflowToDisk:當內存中對象數量達到 maxElementsInMemory 時,Ehcache 將會對象寫到磁盤中
    • diskSpoolBufferSizeMB:這個參數設置 DiskStore(磁盤緩存)的緩存區大小,默認是30MB,每個Cache都應該有自己的一個緩沖區
    • maxElementsOnDisk:硬盤最大緩存個數
    • diskPersistent:是否緩存虛擬機重啟期數據
    • diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒
    • memoryStoreEvictionPolicy:當達到 maxElementsInMemory 限制時,Ehcache 將會根據指定的策略去清理內存,默認策略是LRU,可以設置為 FIFO 或是 LFU
    • clearOnFlush:內存數量最大時是否清除

    開啟緩存

    @EnableCaching @SpringBootApplication public class EhcacheApplication {public static void main(String[] args) {SpringApplication.run(EhcacheApplication.class, args);} }

    具體使用方法和 Redis 類似

    No.12 Spring Boot 定義系統啟動任務

    在傳統 Java Web 項目中,如果設計到系統任務(只在項目啟動時運行的任務),一般用會用到 Listener,定義一個 ServletContextListener,通過這對象就可以監控到項目的啟動和銷售,做出對應的操作。

    1、CommandLineRunner

    使用 CommandLineRunner 時,首先自定義 MyCommandLineRunner1 并且實現 CommandLineRunner 接口:

    @Component @Order(100) public class MyCommandLineRunner1 implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {for (String s: args) {System.out.print(s + " ");}System.out.println();} }

    首先通過 @Componment 注解將 MyCommandLineRunner1 注冊為 Spring 容器的一個 bean,@Order 表示啟動的優先級,值越小優先級越高,run 方法的參數來自于項目的啟動參數

    IDEA 通過如下方式傳遞參數

    另一種方式,則是將項目打包,在命令行中啟動項目,然后啟動時在命令行傳入參數,如下:

    java -jar runner-0.0.1-SNAPSHOT.jar 大哥 22

    2、ApplicationRunner

    ApplicationRunner 和 CommandLineRunner 功能一致,用法也基本一致,唯一的區別主要體現在對參數的處理上,ApplicationRunner 可以接收更多類型的參數(ApplicationRunner 除了可以接收 CommandLineRunner 的參數之外,還可以接收 key/value形式的參數)。

    使用 ApplicationRunner ,自定義類實現 ApplicationRunner 接口即可,組件注冊以及組件優先級的配置都和 CommandLineRunner 一致,如下:

    @Component @Order(98) public class MyCommandLineRunner2 implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println(args.getNonOptionArgs());System.out.println(args.getOptionNames());System.out.println(args.getOptionValues("age"));for (String s: args.getSourceArgs()) {System.out.print(s + " ");}System.out.println();} }

    關于參數:

    • args.getNonOptionArgs(); 可以用來獲取命令行的無 key 參數
    • args.getOptionNames(); 獲取 key/value 形式的參數的 key 的集合
    • args.getOptionValues(key)); 根據 key 獲取 key/value 形式的參數的 value
    • args.getSourceArgs(); 獲取命令行中的所有參數

    傳參和 CommandLineRunner 相同

    No.13 Spring Boot 整合 MyBatis

    創建項目,引入 web、mybatis、mysql、druid

    配置 application.properties

    spring.datasource.url=jdbc:mysql:///test?serverTimezone=GMT spring.datasource.username=root spring.datasource.password=123456 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

    創建 Mapper:

    @Repository public interface UserMapper {@Results({@Result(property = "id", column = "id"),@Result(property = "userName", column = "user_name"),@Result(property = "password", column = "password"),@Result(property = "telPhone", column = "tel_phone")})@Select("select * from user")public List<User> findAll();@Select("select * from user where id = #{id}")public User findUserById(Long id);@Update("update user set user_name=#{userName}, password = #{password}, tel_phone=#{telPhone} where id = #{id}")public Integer updateUserById(User user);@Insert("insert into user(user_name, password, tel_phone) values(#{userName}, #{password}, #{telPhone})")public Long insertUser(User user); }

    配置好 UserMapper 之后還需要配置 Mapper 掃描,可以在該類上標注 @Mapper,將該類標注為一個 Mapper 接口,當然更優雅的方式是在啟動類上配置,如下:

    @MapperScan(basePackages = "com.kernel.mapper") @SpringBootApplication public class MybatisApplication {public static void main(String[] args) {SpringApplication.run(MybatisApplication.class, args);} }

    No.14 Spring Boot 多數據源配置之 JdbcTemplate

    創建項目,引入 web、jdbc、mysql、druid

    創建 Bean:

    public class User {private Long id;private String userName;private String password;private String telPhone; }

    配置 application.yml

    spring:datasource:one:url: jdbc:mysql///testusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSourcetwo:url: jdbc:mysql///testusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSource

    這里對數據源的名字進行了區分,但是這樣的話就沒法手動配置了,所以需要手動配置一下,我們創建一個 DataSourceConfig:

    @Configuration public class DataSourceConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource.one")DataSource dataSource1() {return DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.two")DataSource dataSource2() {return DruidDataSourceBuilder.create().build();} }

    配置 JdbcTemplate 實例

    @Configuration public class JdbcTemplateConfig {@BeanJdbcTemplate jdbcTemplateOne(@Qualifier("dataSource1")DataSource dataSource) {return new JdbcTemplate(dataSource);}@BeanJdbcTemplate jdbcTemplateTwo(@Qualifier("dataSource2")DataSource dataSource) {return new JdbcTemplate(dataSource);} }

    每個 JdbcTemplate 的創建都需要 DataSource ,我們項目中提供了兩個 DataSource,如果按照類型自動注入會報錯,所以使用 @Qualifier 按名稱查找

    至此,JdbcTemplate 多數據源就配置完成了

    No.15 Spring Boot 整合 MyBatis 多數據源

    創建項目,引入 web、mybatis、mysql、druid

    配置 application.properties

    spring.datasource.one.url=jdbc:mysql:///test?serverTimezone=GMT spring.datasource.one.username=root spring.datasource.one.password=123456 spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.two.url=jdbc:mysql:///test?serverTimezone=GMT spring.datasource.two.username=root spring.datasource.two.password=123456 spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource

    提供兩個 DataSource,如下:

    @Configuration public class DataSourceConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource.one")DataSource dsOne() {return DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.two")DataSource dsTwo() {return DruidDataSourceBuilder.create().build();} }

    配置 數據源:

    @Configuration @MapperScan(basePackages = "com.kernel.mybatis.mapper1", sqlSessionFactoryRef = "sqlSessionFactoryOne", sqlSessionTemplateRef = "sqlSessionTemplateOne") public class MyBatisConfigOne {@Resource(name = "dsOne")DataSource dataSource;@BeanSqlSessionFactory sqlSessionFactoryOne() {SqlSessionFactory sqlSessionFactory = null;try {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);sqlSessionFactory = bean.getObject();} catch (Exception e) {e.printStackTrace();}return sqlSessionFactory;}@BeanSqlSessionTemplate sqlSessionTemplateOne() {return new SqlSessionTemplate(sqlSessionFactoryOne());} }

    首先這是個配置類,配置要掃描的包的范圍,配置 sqlSessionFactory 和 sqlSessionTemplate

    根據上面配置第二個數據源:

    @Configuration @MapperScan(basePackages = "com.kernel.mybatis.mapper2", sqlSessionFactoryRef = "sqlSessionFactoryTwo", sqlSessionTemplateRef = "sqlSessionTemplateTwo") public class MyBatisConfigTwo {@Resource(name = "dsTwo")DataSource dataSource;@BeanSqlSessionFactory sqlSessionFactoryTwo() {SqlSessionFactory sqlSessionFactory = null;try {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);sqlSessionFactory = bean.getObject();} catch (Exception e) {e.printStackTrace();}return sqlSessionFactory;}@BeanSqlSessionTemplate sqlSessionTemplateTwo() {return new SqlSessionTemplate(sqlSessionFactoryTwo());} }

    總結

    以上是生活随笔為你收集整理的一文入门 Spring Boot的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    欧美日韩国产一区二 | 久久人人爽人人爽 | 久草在线免费资源站 | 免费人成在线观看 | 久草男人天堂 | 成人毛片一区 | 国内久久精品视频 | 亚洲午夜精品在线观看 | 热九九精品 | 国产在线观看,日本 | 亚洲少妇天堂 | 国产精品18久久久久久久 | 天天插天天狠 | 国产成人久久精品一区二区三区 | 成人福利在线播放 | 91网址在线| 久草精品视频 | 免费久久网站 | 五月婷婷视频在线 | 17videosex性欧美| 五月婷婷开心 | 国产精品欧美 | 亚洲精品一区中文字幕乱码 | 欧美日韩一区久久 | 尤物九九久久国产精品的分类 | 免费在线国产精品 | 欧美一级艳片视频免费观看 | 激情在线五月天 | av一级片在线观看 | 中文字幕乱码日本亚洲一区二区 | 久久人人爽人人爽人人片av软件 | 激情综合狠狠 | 激情五月婷婷激情 | 字幕网av | 九九热在线视频 | 香蕉视频网站在线观看 | 欧美三级高清 | 91成人看片| 欧美色图另类 | 永久中文字幕 | 高清色免费 | 久久深爱网 | 日韩乱理 | 久久se视频 | 亚洲欧美视频在线观看 | 亚洲激情网站免费观看 | 久久久香蕉视频 | 欧美91视频| 国产 欧美 日产久久 | 九月婷婷色 | 成年免费在线视频 | 国偷自产视频一区二区久 | 91在线欧美| 国产免费精彩视频 | 一区二区三区动漫 | 国产婷婷 | 国产精品免费小视频 | a成人v在线 | 婷婷丁香av| 日日碰狠狠躁久久躁综合网 | 欧美精品一区在线 | 精品福利片| 日本超碰在线 | 午夜天使 | 亚洲精品黄网站 | 超碰免费97| 国产资源在线免费观看 | 成人午夜电影网 | 91.dizhi永久地址最新 | 免费影视大全推荐 | 天天插天天色 | 91亚洲精品国偷拍自产在线观看 | 婷婷丁香在线观看 | 99视频精品视频高清免费 | 亚洲三级黄色 | 操操操日日 | 一区二区视频在线观看免费 | 日韩视频在线播放 | 国产亚洲精品美女久久 | 久久人91精品久久久久久不卡 | 亚洲成人免费观看 | 亚洲最快最全在线视频 | 国产大尺度视频 | 精品国模一区二区三区 | 亚洲精品在 | 97**国产露脸精品国产 | 日本高清dvd| 91精品伦理 | 公与妇乱理三级xxx 在线观看视频在线观看 | 成人av在线观 | 成人精品99 | 伊人影院得得 | 亚洲国内精品在线 | 久久伦理电影网 | 亚洲理论片 | 欧美在线91 | 四虎成人免费观看 | 天天操月月操 | 日韩网站在线观看 | 国产超碰在线 | 亚洲国产成人精品在线观看 | 人人澡人人爽欧一区 | 国产亚洲人成网站在线观看 | 国产麻豆精品一区二区 | 亚洲国产一区在线观看 | 亚洲国产精品传媒在线观看 | 久久久国产精品网站 | 日本精品免费看 | www操操| 国产91精品高清一区二区三区 | 江苏妇搡bbbb搡bbbb | 精品国产伦一区二区三区观看说明 | 国产美女主播精品一区二区三区 | 天天操比 | 973理论片235影院9 | 中文在线a∨在线 | av中文字幕网站 | 日韩欧美在线免费观看 | 久久精品123 | 精品国产伦一区二区三区观看体验 | 激情在线五月天 | 国语久久 | 免费a级黄色毛片 | 亚州精品在线视频 | 欧洲黄色片 | 日韩欧美在线高清 | 国产自产在线视频 | 国产精品av在线 | 六月色婷婷 | 五月天中文字幕 | 99久高清在线观看视频99精品热在线观看视频 | av在线官网| 色a综合 | 美女黄频 | 91丨精品丨蝌蚪丨白丝jk | 日韩在线观看影院 | www.99在线观看 | 亚洲国产精品久久久久 | 亚洲精品网站在线 | 日日夜日日干 | 在线观看激情av | 91成版人在线观看入口 | 久久在线| 色a4yy| 亚洲a色| 成人av在线直播 | 精品一二三四在线 | 国产精品破处视频 | 亚洲精品国产欧美在线观看 | 国内免费久久久久久久久久久 | 国产成在线观看免费视频 | 天海翼一区二区三区免费 | 欧美91精品 | 国产福利在线免费观看 | 黄色毛片一级片 | 99在线视频网站 | 江苏妇搡bbbb搡bbbb | 夜夜摸夜夜爽 | 一区二区不卡视频在线观看 | 夜色成人av | 中文字幕视频一区二区 | 精品国产免费观看 | 亚洲精品乱码白浆高清久久久久久 | 免费高清无人区完整版 | 在线免费观看视频a | 国产一级免费片 | 日韩精品无| 中文字幕一区二区三区四区视频 | 国产精品久久久久久久午夜片 | 天天操天天干天天插 | 99精品免费久久久久久久久日本 | 亚洲高清视频在线观看 | 福利网址在线观看 | 精品中文字幕在线 | 亚洲电影自拍 | 国内精品久久久久影院一蜜桃 | 99热超碰 | 免费福利视频网站 | a级国产片 | 久久毛片网 | 欧美一级黄色片 | 综合网色| 日韩视频在线观看视频 | 久久久久在线观看 | 在线视频一区二区 | 欧美一区影院 | 亚洲精品456在线播放 | 韩国av免费在线观看 | 91精品在线免费 | 久久久久观看 | 国语久久 | 欧美日韩高清在线一区 | 日本黄区免费视频观看 | 国产午夜麻豆影院在线观看 | 亚洲日本在线一区 | 成人av直播 | 国产精品欧美久久久久三级 | 久久av观看 | 久草在线视频网站 | 久久亚洲综合国产精品99麻豆的功能介绍 | 亚洲六月丁香色婷婷综合久久 | 丁香六月婷 | 又粗又长又大又爽又黄少妇毛片 | 亚洲日本精品视频 | 久草精品免费 | 国产精品一区久久久久 | 久久精品久久精品久久精品 | 国产在线999 | 色综合久久88 | 久久任你操 | 热久久免费视频 | 久久久久久久免费看 | 日本精品午夜 | 天天鲁天天干天天射 | 91av中文字幕 | 天堂在线免费视频 | 爱射综合 | av在线日韩| 丰满少妇对白在线偷拍 | 欧美日韩高清 | 日韩av中文字幕在线免费观看 | 国产乱码精品一区二区蜜臀 | 日韩三区在线观看 | 天天操天天操天天操天天操天天操天天操 | 亚洲一级久久 | 久久系列 | 亚洲欧美经典 | 国产系列在线观看 | 日韩理论在线视频 | 日韩欧美一区二区在线播放 | 亚洲 欧美 另类人妖 | 97色婷婷人人爽人人 | 久久综合射 | 999精品网 | 福利一区二区三区四区 | 草久视频在线 | 国产午夜在线观看视频 | 国产精品av在线免费观看 | 久久er99热精品一区二区 | 欧美激情第28页 | 中文字幕在线视频一区 | av千婊在线免费观看 | 天天操天天操天天操天天操天天操 | 粉嫩av一区二区三区四区五区 | 波多野结衣精品在线 | 国产成人精品日本亚洲999 | 88av网站 | 婷婷夜夜| 久久久在线观看 | 欧美在线观看视频一区二区三区 | 激情婷婷在线 | 久草视频在线免费播放 | 丁香婷婷色综合亚洲电影 | 成人影视免费 | 日韩高清不卡在线 | 精品影院| 奇米影视777影音先锋 | 啪啪小视频网站 | 天天射天天艹 | 在线观看麻豆av | 99久久激情 | 在线不卡的av | 91黄视频在线观看 | 五月天久久婷 | 香蕉视频网站在线观看 | 国产精品不卡在线观看 | av三级av| 69精品人人人人 | 国产精品久久久久久久久久三级 | 91大神电影 | 成人黄色片免费看 | 日韩区在线观看 | 96久久精品 | 国产一区电影在线观看 | 国产在线观看国语版免费 | 亚洲午夜久久久影院 | av软件在线观看 | 成人影片免费 | 欧美精品一区二区免费 | 91福利视频一区 | 国产午夜三级一区二区三桃花影视 | 国内成人精品2018免费看 | 久精品视频在线观看 | 美女黄频视频大全 | 亚洲专区视频在线观看 | 久久免费看 | 色婷婷五 | 国产精品福利在线观看 | 97成人在线观看视频 | 国产精品欧美一区二区三区不卡 | 亚洲国产精品女人久久久 | 91精品对白一区国产伦 | 在线免费色视频 | 成人国产一区二区 | 欧美成人tv| www.国产毛片 | 丁香五婷 | 国产成人精品久 | 久草在线视频在线观看 | 成人欧美亚洲 | 中文字幕久久网 | 超碰在线观看av.com | 激情欧美在线观看 | 日日干av | 日本99热| 日韩免费观看高清 | 久久午夜免费视频 | 亚洲精品久久久蜜臀下载官网 | 99久久婷婷国产一区二区三区 | 国产美女精品视频免费观看 | av在线播放亚洲 | 最新免费中文字幕 | 国产又粗又猛又爽又黄的视频先 | 国产美女被啪进深处喷白浆视频 | 黄色精品视频 | 青青久草在线视频 | 亚洲国产精品成人女人久久 | 日本精品久久久久中文字幕5 | 久久综合九色综合97_ 久久久 | 国产中文在线视频 | 91精品啪啪 | 婷婷激情影院 | 免费在线观看国产黄 | 韩日精品视频 | 国产麻豆果冻传媒在线观看 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 免费视频久久 | 亚洲精品乱码久久久久久蜜桃欧美 | 色婷婷激情电影 | 日韩电影久久久 | 欧美激情综合五月色丁香小说 | 91精品一区国产高清在线gif | 亚洲精品mv在线观看 | 欧美一级艳片视频免费观看 | 中文字幕亚洲字幕 | 日韩在线观看中文 | 日韩中文幕 | avove黑丝 | 亚洲精品中文字幕视频 | 日韩在线国产 | 麻豆视频免费看 | 亚洲五月激情 | 久久久综合九色合综国产精品 | 在线观看日本高清mv视频 | 国产精品白浆 | 天天干天天干天天干天天干天天干天天干 | 国内精品免费久久影院 | 激情六月婷婷久久 | 一区二区三区视频在线 | 九九久久免费视频 | 91av九色| 丁香视频五月 | 欧美激情综合色 | 免费国产黄线在线观看视频 | 日日爱999 | 狠狠色伊人亚洲综合网站色 | 国偷自产视频一区二区久 | 国内精品美女在线观看 | 欧美午夜a| 91精品国产三级a在线观看 | 国产成人精品不卡 | 久久成人精品电影 | 99精品视频在线看 | 国产一级在线 | 亚洲一区二区视频 | 黄色不卡av | 天天躁天天躁天天躁婷 | 久热超碰 | 欧美成年人在线视频 | 欧美日韩高清一区二区 国产亚洲免费看 | 国产精品久久99精品毛片三a | 国产91精品看黄网站在线观看动漫 | 超碰免费观看 | 超碰97中文| 美女黄久久 | 国产成人精品日本亚洲999 | 四虎影视成人精品 | 超碰97中文 | 手机av在线免费观看 | 婷婷在线色 | 欧美激情综合色综合啪啪五月 | 区一区二在线 | 男女免费视频观看 | 国产精品手机在线 | 五月天久久 | 久久精彩免费视频 | 免费观看午夜视频 | 久草在线视频网 | 91视频传媒 | 国产精品一区二区免费看 | 九九精品视频在线看 | 手机在线看a | 九九热在线精品视频 | 日韩精品电影在线播放 | 在线看国产视频 | 午夜在线观看一区 | 日韩免费成人av | 午夜国产一区二区 | 香蕉久久久久久久 | 国产精品精 | 久久高清视频免费 | 91探花国产综合在线精品 | 一区二区三区动漫 | 国产精品久久久久久欧美 | 99视频在线观看视频 | 国产超碰97 | 国产精品第一 | 日本大尺码专区mv | 国产亚洲精品久久19p | 五月婷婷一区 | 国产精品一区二区吃奶在线观看 | 99一级片| 99精品电影 | av一区二区在线观看中文字幕 | 日韩最新在线视频 | 人人添人人澡人人澡人人人爽 | 欧美一区二区在线免费看 | 国产精品99久久久久久小说 | 欧美大片在线看免费观看 | 亚洲视频精品 | 日韩高清毛片 | av电影免费观看 | 成片免费观看视频大全 | 成人一级在线观看 | 国产亚洲欧美精品久久久久久 | 国产99视频在线观看 | 日韩影视精品 | 亚洲免费一级电影 | 国产精品九九视频 | 欧美色操 | 在线免费视频 你懂得 | 91av色| 国产精品久久久久一区 | 91看片淫黄大片一级在线观看 | 成年人在线观看网站 | 天天射天天操天天色 | 午夜久久久久久久 | 欧美久久久久久久久久久久久 | 九九久久在线看 | 久久高清免费视频 | 丁香激情综合久久伊人久久 | 日韩av影视在线观看 | av三级在线免费观看 | 中文字幕二区三区 | 国产黄色资源 | 91精品国产91久久久久久三级 | 欧美日韩国产精品久久 | www.亚洲激情.com | av在线短片| 国产视频1区2区 | 成人一级视频在线观看 | 狠狠干天天操 | 久久国产精品精品国产色婷婷 | 精品在线亚洲视频 | 成人免费看视频 | 亚洲涩涩网 | 日韩精品无码一区二区三区 | 成人毛片在线视频 | 成人一级片视频 | 欧美日韩在线观看视频 | 天天干夜夜操视频 | a国产精品| 网址你懂的在线观看 | 久久伊人婷婷 | 亚洲 欧美 精品 | 娇妻呻吟一区二区三区 | 黄a网站| 免费观看一区二区 | 麻豆免费看片 | 日韩伦理片hd| 香蕉影院在线观看 | 国产亚洲在线 | 免费热情视频 | 999久久久精品视频 日韩高清www | 国产精品欧美精品 | 久草在线视频网站 | 欧美日韩免费在线观看视频 | 国产精品毛片 | 国产+日韩欧美 | 日韩欧美在线影院 | 日批视频 | 久久伦理电影 | 久久久精品| 成人91在线观看 | 成人在线视频你懂的 | 久久久久久片 | 一区二区三区在线观看中文字幕 | 免费国产在线视频 | 免费黄色在线 | 成人av资源 | 欧美资源| 亚州精品视频 | 天天草天天草 | 男女视频久久久 | 青草视频在线 | 中文字幕av全部资源www中文字幕在线观看 | 四虎成人在线 | 国产最新在线 | 日韩电影在线看 | 精品99免费| 亚洲精品一区二区在线观看 | 国产美女久久久 | 狠狠操导航 | 国产99久久精品一区二区300 | 亚洲在线视频免费观看 | 欧美日在线观看 | 国产精品手机视频 | 又爽又黄又无遮挡网站动态图 | 亚洲性xxxx| 亚洲激情 在线 | 亚洲在线看 | 久久视频6 | 免费成人在线观看 | 黄色免费观看 | 中中文字幕av在线 | 66av99精品福利视频在线 | 日韩中文字幕免费电影 | 国产在线精品视频 | 国产精品免费一区二区三区在线观看 | 黄色在线观看污 | 最新av在线网址 | 中文字幕视频免费观看 | 成人毛片网 | 成人动漫一区二区 | 中文字幕激情 | 国产成人av一区二区三区在线观看 | 麻豆视频免费在线观看 | 欧美一区影院 | 99热官网 | 三上悠亚在线免费 | 麻豆视频在线观看免费 | 久久99精品波多结衣一区 | 久久免费视频4 | 在线 国产 日韩 | 中文字幕精品一区久久久久 | 成年人国产视频 | 午夜电影av| 国产精品久久片 | 国产一区二区久久精品 | 精品国产91亚洲一区二区三区www | 久久综合九色综合97婷婷女人 | 日韩69视频 | 一区二区精品在线观看 | 免费成人av在线看 | 日韩精品视频在线观看免费 | 国产99久久九九精品免费 | 国产视频2区 | 天天操夜夜操夜夜操 | 日韩黄视频 | 日韩视频一二三区 | 日韩欧美中文 | 日韩精品一区电影 | 国产午夜小视频 | 6699私人影院| 日韩精品大片 | 天天爽网站 | 欧美日韩亚洲在线观看 | 2018亚洲男人天堂 | 97在线观看免费视频 | 国产区高清在线 | 中文在线最新版天堂 | 66av99精品福利视频在线 | 午夜久久影视 | 色综合天天视频在线观看 | 在线亚洲日本 | 精品久久电影 | 91高清在线| 97超视频| 日韩精品不卡 | 黄色小说在线免费观看 | 国产一区二区不卡视频 | 国产又粗又硬又长又爽的视频 | 中文字幕在线免费看 | 日日夜夜网 | 亚洲综合国产精品 | 92精品国产成人观看免费 | 成人cosplay福利网站 | 亚洲欧美成人综合 | 婷婷久久丁香 | 日色在线视频 | 中文字幕电影在线 | 久久人人做 | 91日韩免费| 国产成人av网址 | 91视频大全 | 国产青青青 | 在线中文字母电影观看 | www蜜桃视频| 午夜影院三级 | 亚洲欧美日韩在线一区二区 | 丁香九月婷婷 | 日韩中文三级 | 国产一区在线免费观看视频 | 亚洲久草在线视频 | 色婷婷国产在线 | 69av在线视频 | 精品 激情 | 亚洲免费成人av电影 | 国产一在线精品一区在线观看 | 91精品老司机久久一区啪 | 精品福利在线视频 | 日日干天天爽 | 欧美视频在线二区 | 狠狠狠色狠狠色综合 | 亚洲区精品视频 | 97成人在线观看 | 96av麻豆蜜桃一区二区 | 天天干夜夜夜操天 | 中文字幕在线观看国产 | 国内成人精品2018免费看 | 国产色婷婷在线 | 欧美精品久久久久久久久久丰满 | www.久久免费视频 | 黄色小网站在线观看 | 日韩中文三级 | 色天天综合网 | 天天干中文字幕 | 福利一区二区 | 久久伦理电影 | 婷婷激情影院 | 99久久精品电影 | 成人免费中文字幕 | 免费黄色网止 | 亚洲欧美日韩国产一区二区三区 | 久一在线 | 久久久久久国产一区二区三区 | 在线v | 97在线观视频免费观看 | 黄色一区二区在线观看 | bayu135国产精品视频 | 91成人免费看片 | 激情五月婷婷丁香 | 亚洲精品久久久久久国 | 不卡的av中文字幕 | 久久国产精品色av免费看 | 日韩欧美网站 | 黄a在线| 国产成人精品亚洲 | 97综合在线 | 九九欧美视频 | 午夜视频在线观看一区二区三区 | 狠狠色伊人亚洲综合网站色 | 国产不卡在线观看视频 | 日韩欧美在线综合网 | 精品免费久久久久久 | 国产成人精品亚洲日本在线观看 | 亚洲精品9 | 成年人免费看的视频 | 99视屏| 91精品国产入口 | 91网站观看 | 国产理论片在线观看 | 日韩三级一区 | 五月婷婷激情网 | 91在线看片 | 久久久亚洲精华液 | 欧美日韩国产综合网 | 精品欧美乱码久久久久久 | 久久艹99 | 国产99亚洲 | 在线观看av片| 最近高清中文字幕在线国语5 | 日韩一区二区三区不卡 | 亚洲精品乱码久久久久久高潮 | 91一区一区三区 | 国产专区日韩专区 | 免费观看完整版无人区 | 亚洲精品国内 | 久久久久久久久毛片 | 91av免费看 | 免费黄av| 日韩av电影中文字幕 | 亚洲尺码电影av久久 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 一区二区三区在线免费观看 | 国产亚洲小视频 | 久久成人高清视频 | 欧美日韩视频在线一区 | 国产精品美女久久久久久2018 | 亚洲成人av片在线观看 | www国产亚洲精品久久网站 | 中文字幕九九 | 波多野结衣一区 | 69欧美视频 | 欧美激情综合色综合啪啪五月 | 天天干天天干天天干 | 99精品视频在线播放观看 | 免费观看一级成人毛片 | 狠狠色丁香久久婷婷综合_中 | 视频成人永久免费视频 | 久久激五月天综合精品 | 69国产在线观看 | 99国内精品久久久久久久 | 国产成人一区二区三区在线观看 | 狠狠操狠狠干天天操 | 国产亚洲精品美女久久 | 一本一本久久a久久精品牛牛影视 | 欧美俄罗斯性视频 | 视频国产一区二区三区 | 啪啪小视频网站 | 九九热免费观看 | 日韩精品视频免费专区在线播放 | 婷婷激情五月 | 国产精品久久久久毛片大屁完整版 | 精品一区二区三区久久久 | 视频国产在线观看18 | 在线影院 国内精品 | 国产精品久久一区二区三区不卡 | 在线观看黄色av | 在线免费黄色 | 久久在线看 | 国产不卡在线播放 | 我要看黄色一级片 | 91久久爱热色涩涩 | 成人av免费在线看 | 欧美日韩免费看 | 免费看片黄色 | 成人av在线网址 | 久久精品视频在线播放 | 91久久国产露脸精品国产闺蜜 | 奇米影音四色 | 久久国产精品系列 | 成人国产精品入口 | 日韩精品不卡 | 亚洲国产精品va在线看黑人动漫 | 九九在线视频免费观看 | av888.com| 综合久久精品 | 国产精品视频全国免费观看 | 五月婷婷综合在线视频 | 国产在线一区二区三区播放 | 婷婷av网 | 色丁香久久 | 亚洲精品黄色 | 欧美性生活大片 | 国内精品久久久久久久久 | 精品国产伦一区二区三区观看体验 | 97av色| 国产精品一区二区中文字幕 | 中文字幕在线国产精品 | 狠狠干成人综合网 | 色夜视频| 国内99视频 | 99亚洲视频 | 日韩欧美高清一区二区三区 | 国产99久久精品一区二区300 | 欧美在线aaa| 亚洲精品女人久久久 | 91视频-88av| 天堂av在线网站 | 亚洲天天综合网 | 最新国产精品拍自在线播放 | 91九色国产蝌蚪 | 日韩精品免费在线视频 | 婷婷日韩| 亚洲 精品在线视频 | 四虎影视欧美 | 日韩a在线观看 | 欧美日韩高清国产 | 久草免费色站 | 国内久久视频 | 黄色一级在线观看 | 久久久久亚洲精品成人网小说 | 综合网伊人 | 日韩精品一区二区免费视频 | 久久精彩免费视频 | 91pony九色丨交换 | 蜜臀av性久久久久蜜臀aⅴ流畅 | www一起操 | 亚洲综合五月天 | 免费av在| 色综合夜色一区 | 深爱激情五月网 | 国产在线视频一区二区三区 | 99久久精品无码一区二区毛片 | 美女视频黄是免费的 | 免费看片在线观看 | av成人在线播放 | 欧美日韩中文在线视频 | 美女在线免费视频 | 日日婷婷夜日日天干 | 日韩一区视频在线 | 97操操| 欧美日韩国产成人 | 国产午夜精品免费一区二区三区视频 | 88av视频| 伊人影院av | 成年美女黄网站色大片免费看 | 99精品国自产在线 | 国产一区二区在线影院 | 亚洲一区二区麻豆 | 久久专区 | 国产美女精品视频免费观看 | 久久狠狠一本精品综合网 | 在线看日韩 | 欧美一区二区在线刺激视频 | 精品视频免费播放 | 91欧美日韩国产 | 精品国产一区二区久久 | 欧美性猛片, | 一区二区视频电影在线观看 | 免费av在线播放 | 91高清完整版在线观看 | 顶级欧美色妇4khd | 国产一区网 | 超碰97成人| 国产精品色婷婷视频 | 二区三区精品 | 亚洲欧美在线观看视频 | 久久国产精品一区二区三区 | 精品毛片一区二区免费看 | 69中文字幕 | 97视频入口免费观看 | 国语精品免费视频 | 亚洲伦理中文字幕 | 精品国产乱码久久 | 91九色视频国产 | 日韩精品一区二区久久 | 国产不卡网站 | 国产日韩高清在线 | 美女av免费 | 久久久久久国产一区二区三区 | 国产传媒一区在线 | 日韩成人精品一区二区三区 | 我要看黄色一级片 | 国产精品永久免费观看 | 五月视频 | 亚洲成人av在线 | 国产系列精品av | 亚洲激情在线播放 | 91视频电影 | 日韩精品一区二区三区三炮视频 | 亚洲欧洲国产视频 | 国产破处精品 | 日韩影视大全 | 亚洲特级片 | 久久婷婷一区二区三区 | 国产精品毛片一区视频播不卡 | 国产欧美最新羞羞视频在线观看 | 狠狠色噜噜狠狠狠狠 | 久久综合九九 | 亚洲天天摸日日摸天天欢 | 国产高清一级 | 密桃av在线 | 欧美伦理一区二区 | 国产精品久久网 | 字幕网在线观看 | 激情五月av | 在线免费观看国产 | 免费黄色网址大全 | 激情久久伊人 | 在线观看免费黄视频 | 手机在线黄色网址 | www.狠狠色.com| 超碰成人网 | 91在线视频免费观看 | 久久九九免费视频 | av免费在线播放 | 一区二区三区四区不卡 | 高清美女视频 | 久久免费视频在线观看6 | 成年人在线免费看 | 最新日韩视频 | 日本性久久 | 久久久久99精品国产片 | 99色资源| 五月婷婷精品 | 欧美视频在线观看免费网址 | 日韩最新在线 | 操久久网 | 日韩久久一区 | 日批网站在线观看 | 日b视频在线观看网址 | 99精品国自产在线 | 久久久久国产成人免费精品免费 | av成人免费网站 | 久久日韩精品 | 成年人免费在线看 | 夜夜躁狠狠躁日日躁 | 日韩欧美视频免费在线观看 | 国产亚洲精品久久久久久久久久久久 | 久久精品国产免费看久久精品 | 亚洲精品国产品国语在线 | 日日夜夜添 | 激情综合国产 | 一本一本久久a久久精品综合 | 婷婷久久综合九色综合 | 免费国产在线精品 | 韩国在线一区 | av免费电影网站 | 一本一道久久a久久综合蜜桃 | 在线免费观看成人 | 久久艹影院 | 日日综合 | 亚欧日韩av | 欧美久久久久久久久久 | 欧美美女视频在线观看 | 日本字幕网 | 狠狠色丁香婷婷综合久小说久 | 久久精品电影院 | 色婷婷www | 国产做爰视频 | 黄色在线观看免费网站 | 亚洲精品乱码久久久久久蜜桃不爽 | 永久免费的av电影 | 国产精品久久久久久久久搜平片 | 国产成人精品一区二区三区在线 | 一个色综合网站 | www免费看片com | 国产成人精品一区二区在线观看 | 99久久电影| 欧美一二三区播放 | 国产特级毛片aaaaaaa高清 | 久久人人97超碰国产公开结果 | 91精品少妇偷拍99 | www.神马久久 | 国产精品成人一区二区三区吃奶 | 97热久久免费频精品99 | 一区二区三区四区五区在线视频 | 国产亚洲精品久久久久久久久久 | 激情综合网五月激情 | 亚洲久久视频 | 丝袜美腿在线视频 | 国产黄色成人 | 日韩 精品 一区 国产 麻豆 | 日本黄色片一区二区 | 中文字幕在线视频国产 | 日韩超碰在线 | 免费看黄网站在线 | 日本天天操 | 国内久久久久久 | 最新av中文字幕 | 国产精品久久久久久久免费 | 91自拍视频在线观看 | 大胆欧美gogo免费视频一二区 | 日韩专区中文字幕 | 最新的av网站 | 久久伊人婷婷 | 成人黄大片视频在线观看 | 91精品资源 | 国产精品成人自拍 | 69国产盗摄一区二区三区五区 | 日本激情动作片免费看 | 亚洲精品视频在线观看免费视频 | 久久九九影院 | 免费成人av电影 | 成人av在线一区二区 | 最近高清中文在线字幕在线观看 | www.国产在线视频 | 国产精品视频大全 | 亚洲黄色在线免费观看 | 国产录像在线观看 | 人人爱夜夜操 | 国产xxxx | 99视频精品全部免费 在线 | 亚洲精品久久久久久中文传媒 | 欧美日韩在线免费视频 | 亚洲精品97 | 天天搞天天 | 国产精品永久免费 | 久久综合婷婷国产二区高清 | 国产精品亚洲综合久久 | 在线天堂中文在线资源网 | 一区三区在线欧 | 黄色一级性片 | 美女视频黄频 | 国产亚洲免费观看 | 日韩激情中文字幕 | 亚洲第一av在线播放 | 在线视频 亚洲 | 98超碰在线| 国产玖玖精品视频 | 欧美日韩中文视频 | 久久久久久久久久久久久久免费看 | 国产偷在线 | a级免费观看 | 成人97视频一区二区 | 青青河边草手机免费 | 人人爱夜夜操 | 国产在线观看免费av | 少妇啪啪av入口 | 黄色成年片| 丁香狠狠 | 在线视频观看成人 | 一级黄色片毛片 | 国产一区福利 | 精品国产午夜 | 91在线视频 | 久草视频在线免费播放 | 在线观看视频你懂的 | 美女搞黄国产视频网站 | 久精品视频免费观看2 | 天天鲁一鲁摸一摸爽一爽 | 一区二区三区在线观看免费视频 | 一区二区三区在线观看中文字幕 | 成人午夜电影网站 | 91丨九色丨国产在线观看 | 成人精品国产免费网站 |