springboot 的默認配置
JDBC
DataSourceProperties 配置類
DataSourceAutoConfiguration 自動掃描
servlet
容器
ServletWebServerFactoryAutoConfiguration
ServerProperties
Springmvc
配置
WebMvcAutoConfiguration
WebMvcProperties
總結:每一個自動配置類xxxAutoConfiguration 都有一個對應的xxxProperties
5.2靜態資源映射規則
可通過分析 WebMvcAutoConfiguration 自動配置類得到
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache()
.getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
}
5.2.1webjars
資源映射
-
所有
/webjars/**
請求,都去classpath:/META-INF/resources/webjars/
目錄找對應資源文件 -
http://localhost:8080/webjars/jquery/3.4.1/jquery.js
這個可以訪問,靜態資源文件
5.2.2 其他靜態資源映射
-
ResourceProperties 根據請求查找資源文件, 從以下 四個路徑 中 查找( 靜態資源目錄 )
-
當接受到 /** 請求訪問資源時, 會被映射到下面4個 類路徑下的靜態資源目錄中 查找:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
5.2.3歡迎頁映射
5.2.3.1在 WebMvcAuotConfiguration.welcomePageHandlerMapping()
分析 歡迎頁映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ApplicationContext applicationContext) {
return new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext),
applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
5.2.3.2分析後, 會從 4個靜態資源目錄 + 根路徑 / 中 查找 index.html 頁面
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
/: 當前項目根路徑下
5.2.3.3會在 靜態資源目錄下 與 根路徑查找 (按該順序) index.html頁面; 收到 “/**” 請求映射
5.2.3.4訪問 localhost:8080/ 會在上面5個目錄中查找 index.html 頁面(因爲/也屬於 /** )
5.2.4圖標映射
Spring Boot 會在靜態資源目錄下 與 根路徑(按該順序) 查找 faicon.ico 文件
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
/: 當前項目根路徑下
5.3 Thymeleaf
模板引擎
標題5.3.1 引入 Thymeleaf
- pom.xml 加入 Thymeleaf 啓動器
<!-- thymeleaf 模板啓動器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>
5.3.2 使用 Thymeleaf
- 模板文件放在哪裏 ?
@ConfigurationProperties( prefix = "spring.thymeleaf" )
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
}
- 導入
Thymeleaf
的名稱空間
在 html 頁面加上以下名稱空間, 使用 Thymeleaf 時就有語法提示。
<html xmlns:th="http://www.thymeleaf.org">
- 演示
Thymeleaf
語法
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
<h2 >成功</h2>
<!--th:text 設置p標籤的標籤體內容-->
<p th:text="${name}">這裏顯示名字</p>
</body>
</html>
5.33 Thymeleaf
語法
- 參考資料
https://www.yiibai.com/thymeleaf/standardurlsyntax.html
5.4 SpringBoot 熱部署
如何能實現熱部署?
-
關於模板引擎
- 在 Spring Boot 開發環境下禁用模板緩存
#開發環境下關閉thymeleaf模板緩存,
spring.thymeleaf.cache=false
- 添加 Spring Boot Devtools 熱部署依賴
<!--熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
- Intellij IEDA和Eclipse不同,Intellij IDEA必須做一些小調整:
在 Eclipse 中,修改文件後要手動進行保存,它就會自動編譯,就觸發熱部署現象
在Intellij IEDA 中,修改文件後都是自動保存,默認不會自動編譯文件,
需要手動編譯按 Ctrl + F9 (推薦使用)或 Build -> Build Project ;
或者進行以下設置纔會自動編譯(效果不明顯)
(File -> Settings -> Build, Execution, Deployment -> Compiler -> 勾選 Build project automatically)
5.5 分析 SpringMVC 自動配置
Spring Boot 爲 Spring MVC 提供了適用於多數應用的自動配置功能( WebMvcAutoConfiguration
)。
- 在Spring默認基礎上,自動配置添加了以下特性:
引入ContentNegotiatingViewResolver
和BeanNameViewResolver
beans.
- 自動配置了視圖解析器
ViewResolver
(根據方法返回值獲取視圖對象View,視圖對象決定如何渲染?重定向Or 轉發) ContentNegotiatingViewResolver
: 組合所有的視圖解析器的(通過源碼可分析出)
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {
//146行
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
if (requestedMediaTypes != null) {
List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
- 自定義視圖解析器:可以@Bean向容器中添加一個我們自定義的視圖解析器,即可被容器管理使用
/**
* 自定義一個視圖解析器
*/
class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
/**
* 將視圖解析器加入容器
*/
@Bean
public ViewResolver myViewresoler() {
return new MyViewResolver();
}
// DispatcherServlet.doDispatch 斷點後,發送任意請求,可查看已被容器自動管理了
-
自動註冊 Converter , GenericConverter , and Formatter beans。
- Converter :轉換器; 如: 文本類型轉換目標類型, true 轉 boolean類型
- GenericConverter :轉換器,Spring內部在註冊時,會將Converter先轉換爲GenericConverter之後,再統一對GenericConverter註冊。
- Formatter : 格式化器; 如: 2017/12/17 格式化 Date類型
-
對 HttpMessageConverters 的支持。
- SpringMVC 用它來轉換Http請求和響應的;User _json User _xml
- 可以通過@Bean向容器中添加一個我們自定義 HttpMessageConverters ,即可被容器管理使用
- 自動註冊 MessageCodesResolver 。
定義錯誤代碼生成規則 - 對靜態資源的支持,包括對 Webjars 的支持
- 對靜態首頁 index.html 的支持。
- 對自定義 Favicon 圖標的支持。
如果想保留 Spring Boot MVC的特性,而且還想擴展新的功能(攔截器, 格式化器, 視圖控制器等),你可以在你自 定義的WebMvcConfigurer 類上增加 @Configuration 註解。
如果你想全面控制SpringMVC(也就是不使用默認配置功能), 你在自定義的Web配置類上添加 @Configuration 和@EnableWebMvc 註解。
5.6 擴展 SpringMVC 功能(實現WebMvcConfigurer
的方法)
- 擴展一個視圖解析器功能
<mvc:view-controller path="/mengxuegu" view-name="success"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean></bean>
</mvc:interceptor>
</mvc:interceptors>
- 如果想保留 Spring Boot MVC的特性,而且還想擴展新的功能(攔截器, 格式化器, 視圖控制器等),你可以 在你自定義的WebMvcConfigurer 類上增加 @Configuration 註解。
//@EnableWebMvc //不能加這個註解
@Configuration
public class MySpringMvcConfigurer implements WebMvcConfigurer {
/**
* 這個方法的功能是:如果請求爲/liyiruo 會轉發到 success
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/liyiruo").setViewName("success");
}
}
- 自定義WebMvcConfigurer自動配置時會導入;
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class}) - EnableWebMvcConfiguration 繼承了 DelegatingWebMvcConfiguration
- 分析 DelegatingWebMvcConfiguration , 會將所有web配置組件加到WebMvcConfigurerComposite中
- 保留原來的配置類,也添加了新的配置類,所有的WebMvcConfigurer都會一起起作用
- 效果:SpringMVC的自動配置和我們的擴展配置都會起作用;
5.7 全面控制 SpringMVC
- 如果你想全面控制SpringMVC(SpringBoot對SpringMVC的自動配置都廢棄), 在自定義的Web配置類上添加@Configuration 和 @EnableWebMvc 註解。
爲什麼添加了@EnableWebMvc SpringMVC的自動配置都廢棄了
- @EnableWebMvc
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
- 先記住繼承了WebMvcConfigurationSupport類
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3.WebMvcAutoConfiguration
類上的註解
//容器中沒有這個組件的時候,這個自動配置類才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//這個註解
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
@EnableWebMvc 的註解添加後,WebMvcAutoConfiguration類不會注入
5.8 總結 SpringMVC 配置
- 在Spring Boot中自已配置組件的時候,先看容器中有沒有公司自已配置的(@Bean@Component),如果有就用公司自已配置的; 如果沒有,才自動配置.
- 在Spring Boot中會有非常多的xxxConfigurer幫助我們進行擴展配置.
- 在Spring Boot中會有很多的xxxCustomizer幫助我們進行定製配置.
6 項目中的增刪改查
7 SpringBoot 錯誤處理機制
7.1 原理分析
- 底層原理分析ErrorMvcAutoConfiguration
- ErrorPageCustomizer 錯誤頁面定製器
- BasicErrorController 就會接收 /error 請求處理。
- DefaultErrorViewResolver 去解析具體響應的錯誤頁面。
- DefaultErrorAttributes錯誤頁面可獲取到的數據信息
通過 BasicErrorController 的方法中響應的 module 可定位到響應哪些數據,從而引出 ErrorAttributes的實現類 DefaultErrorAttributes , DefaultErrorAttributes 中綁定的所有值都可在頁面獲取到。
- 小技巧:在四個靜態資源文件路經下,創建 error/404.html error/500.html 文件 當發生對應的錯誤時,會跳轉到對應的頁面
7.2 自定義錯誤響應頁面
第1種 :有模板引擎
- error/狀態碼 : 精確匹配,將錯誤頁面命名爲 錯誤狀態碼.html 放在模板引擎目錄 templates 下的 error 目錄下,發生對應狀態碼錯誤時,就會響應對應的模板頁面
- error/4xx 、error/5xx :模糊匹配, 可以將錯誤頁面命名爲 4xx 和 5xx ,有來匹配對應類型的所有錯誤
- 採用精確優先
- 錯誤頁面可獲取的的數據信息
- timestamp:時間戳
- status:狀態碼
- error:錯誤提示
- exception:異常對象
- message:異常消息
- errors:JSR303數據校驗出現的錯誤
第2種:沒有模板引擎 (模板引擎找不到對應錯誤頁面)
第3種: 模板目錄與靜態目錄下都找不到對應錯誤頁面,就響應 SpringBoot 默認的錯誤頁面
通過 BasicErrorController 的 errorhtml 方法最後 一行可知,沒有找到則找 error 視圖對象,error定義 在 ErrorMvcAutoConfiguration 的 defaultErrorView 中
protected static class WhitelabelErrorViewConfiguration {
private final SpelView defaultErrorView = new SpelView(
"<html><body><h1>Whitelabel Error Page</h1>"
+ "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"
+ "<div id='created'>${timestamp}</div>"
+ "<div>There was an unexpected error (type=${error}, status=${status}).</div>"
+ "<div>${message}</div></body></html>");
@Bean(name = "error")
@ConditionalOnMissingBean(name = "error")
public View defaultErrorView() {
return this.defaultErrorView;
}
7.3 自定義數據進行響應
- 分析:
出現錯誤以後,會發送 /error 請求,會被 BasicErrorController 處理,而響應的數據是由getErrorAttributes 封裝的(就是 ErrorController 的實現類 AbstractErrorController.getErrorAttributes 的方法),所以我們只需要自定義 ErrorAttributes 實現類即可
- 自定義 ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String,Object>map=super.getErrorAttributes(webRequest, includeStackTrace);
map.put("company", "liyiruo");
return map;
}
}
- 前端頁面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>500</title>
</head>
<body>
error 500頁面
<h2>[[${company}]]</h2>
<h2>[[${timestamp}]]</h2>
<h2>[[${status}]]</h2>
<h2>[[${message}]]</h2>
<h2>[[${exception}]]</h2>
<h2>[[${error}]]</h2>
</body>
</html>
timestamp=Mon Mar 30 12:58:53 CST 2020
status=500
error=Internal Server Error
message=/ by zero
path=/hello company=liyiruo
第8章 嵌入式Servlet容器自定義配置
8.1 註冊Servlet三大組件 Servlet/Filter/Listener
- Spring提供以下Bean來註冊三大組件:
- ServletRegistrationBean :註冊自定義Servlet
- FilterRegistrationBean :註冊自定義Filter
- ServletListenerRegistrationBean :註冊自定義Listener
- 自定義一個servlet:
public class HelloServlet extends HttpServlet {
//處理get請求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("helloServlet success……");
}
}
- 將servlet加入容器
@Configuration
public class MyServletConfig {
/**
* 註冊servlet組件
*/
@Bean
public ServletRegistrationBean helloServlet() {
ServletRegistrationBean<HelloServlet> bean = new ServletRegistrationBean<>(new HelloServlet(), "/hello");
// bean.setServlet();
// bean.setUrlMappings();
//設置servlet組件的參數
bean.setLoadOnStartup(1);
return bean;
}
- 自定義一個filter
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter初始化操作");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Myfileter過濾完成");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("filter銷燬");
}
}
- 將filter加入容器
@Configuration
public class MyServletConfig {
//將servlet加入容器省略
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
//設置自定義filter
bean.setFilter(new MyFilter());
//走完這個過濾器以後,走下面的路經
bean.setUrlPatterns(Arrays.asList("/hello"));
return bean;
}
}
- 自定義Listener
public class MyListenner implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("監聽器初始化");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("監聽器銷燬");
}
}
- 將Listener加入容器
@Configuration
public class MyServletConfig {
@Bean
public ServletListenerRegistrationBean myListener() {
ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean();
bean.setListener(new MyListenner());
return bean;
}
}
8.2 分析自動註冊的SpringMVC前端控制器
SpringBoot 在 DispatcherServletAutoConfiguration
自動配置中 , 幫我們註冊SpringMVC 的前端控制器:DispatcherServlet
//註冊了一個默認的前端控制器
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(
dispatcherServlet, this.serverProperties.getServlet().getPath());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(
this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
8.3 修改Servlet容器配置
8.3.1 通過配置文件配置
#項目服務相關
server.port=8080
#修改Servlet相關配置 server.servlet.xxx
server.servlet.context-path=/servlet
#修改Tomcat相關配置 server.tomcat.xxx
8.3.2 使用定製器修改Servlet容器配置(spring1.x與spring2.x不同)
在2.x版本改爲實現 WebServerFactoryCustomizer 接口的 customize 方法
@Bean
public WebServerFactoryCustomizer webServerFactoryCustomizer() {
return new WebServerFactoryCustomizer() {
@Override
public void customize(WebServerFactory factory) {
ConfigurableWebServerFactory serverFactory = (ConfigurableWebServerFactory) factory;
serverFactory.setPort(8099);
/*serverFactory.setErrorPages();
serverFactory.setCompression();
serverFactory.setAddress();
serverFactory.setServerHeader();*/
}
};
}
8.4 切換爲其他嵌入式Servlet容器
- SpringBoot 默認針對Servlet容器提供以下支持
- Tomcat(默認使用)
- Jetty :支持長連接項目(如:聊天頁面)
- Undertow : 不支持 JSP , 但是併發性能高,是高性能非阻塞的容器
- 默認Tomcat容器
在spring-boot-starter-web啓動器中默認引入了tomcat容器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
- 切換 Jetty 容器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除tomcat容器 -->
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入其他的Servlet容器-->
<dependency>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
- 切換 Undertow 容器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除tomcat容器 -->
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入其他的undertow容器-->
<dependency>
<artifactId>spring-boot-starter-undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
第9章 使用外置Servlet容器_Tomcat9.x
9.1 比較嵌入式與外置Servlet容器
9.2 使用Tomcat9.x作爲外置Servlet容器
- 必須創建一個 war 類型項目
- idea 上指定web.xml 與 修改好目錄結構
- 指定webapp目錄
- 指定web.xml位置
- 添加外置tomcat
- 在 pom.xml 將嵌入式的Tomcat指定爲provided (Spring初始化器已經默認指定了)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
- Spring初始化器 自動創建了 SpringBootServletInitializer 的子類,調用 configure 方法
- 直接開發項目功能即可, 然後啓動tomcat即可訪問
10.SpringBoot 數據訪問操作
10.1 整合 JDBC 實戰
<!--mysql驅動包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--jdbc啓動器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/jdbc?serverTimezone=GMT%2B8&useSSL=false
username: 'root'
password: '!QAZ2wsx'
# driver-class-name: com.mysql.cj.jdbc.Driver
@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringBoot10JdbcApplicationTests {
@Autowired
DataSource dataSource;
@Test
public void contextLoads() {
}
@Test
public void test2() throws SQLException {
Connection connection = dataSource.getConnection();
System.out.println(connection.getClass());
}
}
SpringBoot 默認採用的數據源連接池是:
com.zaxxer.hikari.HikariDataSource
數據源相關配置都在DataSourceProperties
中;
- 常見錯誤
- 需要配置文件中指定時區:
jdbc:mysql://127.0.0.1:3306/jdbc?serverTimezone=GMT%2B8
- 警告:Establishing SSL connection without server’s identity verification is not recommended。解決方案:
jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
10.2 高級配置 Druid 連接池與監控管理
- 引入依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
- 全局配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/jdbc?serverTimezone=GMT%2B8&useSSL=false
username: 'root'
password: '!QAZ2wsx'
# driver-class-name: com.mysql.cj.jdbc.Driver
# 加入一個type就可以指定數據源了
type: com.alibaba.druid.pool.DruidDataSource
initialSize: 8
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置監控統計攔截的filters,去掉後監控界面sql無法統計,'wall'用於防火牆
filters: stat,wall,logback
maxPoolPreparedStatementPerConnectionSize: 25
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
- 自定義配置類, 將配置中屬性與 DruidDataSource 屬性綁定
- 配置Druid監控
@Configuration
public class DruidConfig {
//返回來的對象的字段被賦值
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource get() {
return new DruidDataSource();
}
//1.配置一個druid的servlet組件
@Bean
public ServletRegistrationBean statViewServlet() {
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
//設置初始化參數
Map<String, String> initParam = new HashMap<>();
//訪問的用戶名密碼
initParam.put(StatViewServlet.PARAM_NAME_USERNAME, "root");
initParam.put(StatViewServlet.PARAM_NAME_PASSWORD, "123");
//允許訪問的ip,默認所有ip訪問
initParam.put(StatViewServlet.PARAM_NAME_ALLOW, "");
//禁止訪問的ip
initParam.put(StatViewServlet.PARAM_NAME_DENY, "192.168.10.1");
bean.setInitParameters(initParam);
return bean;
}
//配置一個過濾器
@Bean
public FilterRegistrationBean filter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//配置初始化參數
Map<String, String> initParam = new HashMap<>();
//排除請求
initParam.put(WebStatFilter.PARAM_NAME_EXCLUSIONS, "*.js,*.css,/druid/*");
bean.setUrlPatterns(Arrays.asList("/"));
return bean;
}
}
10.3 整合 MyBatis3.x 註解版本實戰
10.4 整合 MyBatis3.x 配置文件版實戰
10.5 整合 Spring Data JPA 實戰
10.6 Spring Boot中的事務管理
12 Spring Boot 異步任務與定時任務實戰
- 異步和定時不需要添加依賴,只需要添加註解
@EnableAsync
,@EnableScheduling
即可:
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class SpringBoot11AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot11AsyncApplication.class, args);
}
}
- 異步方法的代碼的編寫
/**
* 異步任務 批量處理
*/
@Service
public class AsyncServer {
@Async
public void batchAdd() {
try {
Thread.sleep(3 * 1000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("批量數據保存中");
}
}
- 異步方法的調用 (正常調用異步的方法)
@RestController
public class AsyncController {
@Autowired
AsyncServer asyncServer;
@RequestMapping("/hello")
public String hello() {
asyncServer.batchAdd();
return "hello";
}
}
- 定時任務代碼的編寫(不需要調用,項目啓用即可執行定時任務)
@Service
public class ScheduledService {
private static int count=0;
@Scheduled(cron = "*/3 * * * * MON-FRI")
public void count() {
System.out.println("第" + count++ + "執行");
}
}
在線生成cron表達式 http://cron.qqe2.com/
13 Spring Boot 郵件發送實戰
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
[email protected]
spring.mail.password=
spring.mail.host=smtp.qq.com
spring.mail.default-encoding=utf-8
spring.mail.properties.smtp.ssl.enable=true
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBoot12EmailApplicationTests {
@Autowired
JavaMailSenderImpl javaMailSender;
@Test
public void contextLoads() {
}
@Test
public void test() {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom("[email protected]");
simpleMailMessage.setTo("[email protected]");
simpleMailMessage.setSubject("test email");
simpleMailMessage.setText("你好啊");
//密送
simpleMailMessage.setBcc("[email protected]");
//抄送人
simpleMailMessage.setCc("[email protected]");
javaMailSender.send(simpleMailMessage);
}
@Test
public void testMimeMail() throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
messageHelper.setSubject("這個是郵件通知");
messageHelper.setFrom("[email protected]");
messageHelper.setTo("[email protected]");
String text = "<!DOCTYPE html>\n" +
"<html>\n" +
"\t<head>\n" +
"\t\t<meta charset=\"utf-8\">\n" +
"\t\t<title></title>\n" +
"\t</head>\n" +
"\t<body>\n" +
"\t\t\t<img alt=\"圖片1\" src=\"http://t9.baidu.com/it/u=4169540006,4220376401&fm=79&app=86&f=JPEG?w=1000&h=1500\" width=\"20%\" height=\"20%\"/>\n" +
"\t\t\t<!-- <img alt=\"圖片2\" src=\"/Users/liyiruo/Desktop/1.jpg\" /> -->\n" +
"\t\t\t<h1 style=\"color: pink;text-align: center;background-color: antiquewhite;\">i love spring</h1>\n" +
"\t</body>\n" +
"</html>\n";
messageHelper.setText(text,true);
messageHelper.addAttachment("只是一個附件名.java",new File("/Users/liyiruo/IdeaProjects/spring-boot-study/spring-boot-12-email/src/main/java/com/liyiruo/springboot/SpringBoot12EmailApplication.java"));
javaMailSender.send(mimeMessage);
}
}
14 Spring Boot 整合緩存實戰
- 引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
- 啓動類上加上註解
@EnableCaching
@EnableCaching
@SpringBootApplication
@MapperScan("com.liyiruo.springboot.mapper")
public class SpringBoot13CacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot13CacheApplication.class, args);
}
}
-
服務類的方法上 加上註解
cacheNames 緩存容器名字
key:緩存容器中的key值,方法返回值是value值
- @CacheConfig(cacheNames = “user”)
- @Cacheable(/cacheNames = “user”,/ key = “#id”)
- @CachePut(/cacheNames = “user”,/ key = “#user.id”)
- @CacheEvict(/cacheNames = “user”,/key = “#id”,allEntries =true,beforeInvocation = false)
@Service
@CacheConfig(cacheNames = "user")
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* cacheNames 緩存容器名字
* key:緩存容器中的key值,方法返回值是value值
*
* @param id
* @return
*/
@Cacheable(/*cacheNames = "user",*/ key = "#id")
public User getUserById(Integer id) {
return userMapper.getUserById(id);
}
//@CachePut(cacheNames = "user",key = "#result.id") //這個也是可以的哦
@CachePut(/*cacheNames = "user",*/ key = "#user.id")
public User updateUser(User user) {
userMapper.updateUser(user);
return user;
}
public Integer addUser(User user) {
return userMapper.addUser(user);
}
/**
* cacheNames 緩存容器的名稱
* key 在容器中的id
* allEntries=true 清除緩存時,清除所有。
* beforeInvocation 執行之前就清除緩存。
* @param id
* @return
*/
@CacheEvict(/*cacheNames = "user",*/key = "#id",allEntries =true,beforeInvocation = false)
public Integer deleteUser(Integer id) {
return userMapper.deleteUser(id);
}
}
- 緩存的實現原理
/**
* 0 = "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"
* 1 = "org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration"
* 2 = "org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration"
* 3 = "org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration"
* 4 = "org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration"
* 5 = "org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration"
* 6 = "org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration"
* 7 = "org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration"
* 8 = "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"[默認緩
存]
* 9 = "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"
* 分析源碼:
* 1.默認採用的是SimpleCacheConfiguration 使用 ConcurrentMapCacheManager
* 2. getCache 獲取的是 ConcurrentMapCache 緩存對象進行存取數據,它使用
ConcurrentMap<Object, Object>對象進行緩存數據
* @Cacheable(cacheNames = "user")
* 第一次請求時:
* 3.當發送第一次請求時,會從cacheMap.get(name)中獲取有沒有ConcurrentMapCache緩存對象,如果沒
有則創建出來,
* 並且創建出來的key就是通過@Cacheable(cacheNames = "user")標識的name值
* 4.接着會從ConcurrentMapCache裏面調用lookup獲取緩存數據,通過key值獲取的,
* 默認採用的是service方法中的參數值,如果緩存中沒有獲取到,則調用目標方法進行獲取數據,獲取之後則再
將它放到緩存中(key=參數值,value=返回值)
*
* 第二次請求:
* 5. 如果再次調用 則還是先ConcurrentMapCacheManager.getCache()獲取緩存對象,如果有則直接返
回,如果沒有則創建
* 6. 然後再調用 ConcurrentMapCache.lookup方法從緩存中獲取數據, 如果緩存有數據則直接響應回去,
不會再去調用目標方法,
*
* 第三次請求與第二次請求一樣.
* 如果緩存中沒有緩存管理器,則與第一次請求一致
*/
15 Spring Boot 整合 Redis 實戰
- 引入包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 添加配置文件(可配置的有很多,其中多數有默認值)
#redis 的相關配置 許多都有默認值
#org.springframework.boot.autoconfigure.data.redis.RedisProperties
spring.redis.host=127.0.0.1
#spring.redis.password=!QAZ2wsx
- 相關的測試代碼 可以設置過期時間
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class SpringBoot13CacheApplicationTests {
@Autowired
StringRedisTemplate stringRedisTemplate;//操作字符串
@Autowired
RedisTemplate redisTemplate;//操作複雜類型
//自定義的json 序列化器
@Autowired
RedisTemplate jsonRedisTemplate;
@Autowired
UserService userService;
@Test
public void test1() {
/*
stringRedisTemplate.opsForValue();
stringRedisTemplate.opsForList();
stringRedisTemplate.opsForHash();
stringRedisTemplate.opsForSet();
stringRedisTemplate.opsForZSet();
*/
stringRedisTemplate.opsForValue().set("mykey", "myvalue");
String mykey = stringRedisTemplate.opsForValue().get("mykey");
User user = userService.getUserById(1);//需要user可序列化
redisTemplate.opsForValue().set("myuser", user);
Object myuser = redisTemplate.opsForValue().get("myuser");
jsonRedisTemplate.opsForValue().set("myuser3", user);
Object myuser2 = jsonRedisTemplate.opsForValue().get("myuser3");
//設置過期時間
redisTemplate.expire(1, 2400, TimeUnit.DAYS);
}
}
- 往redis 存儲複雜類型時,可能需要一個序列化器
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> jsonRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
//增加這一行。
template.setDefaultSerializer(new Jackson2JsonRedisSerializer(Object.class));
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}