javascript
一文入门 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=test3、普通的屬性注入
由于 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 有兩種方式 :
具體定義如下:
@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同源檢測的示例:
| 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)跨站請求偽造。跨站請求偽造也被稱為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 大哥 222、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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用sql语句算两经纬度的距离
- 下一篇: gradle idea java ssm