Springboot 入門教程的 學習總結

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 資源映射

  1. 所有 /webjars/** 請求,都去 classpath:/META-INF/resources/webjars/ 目錄找對應資源文件

  2. http://localhost:8080/webjars/jquery/3.4.1/jquery.js 這個可以訪問,靜態資源文件

5.2.2 其他靜態資源映射

  1. ResourceProperties 根據請求查找資源文件, 從以下 四個路徑 中 查找( 靜態資源目錄 )

  2. 當接受到 /** 請求訪問資源時, 會被映射到下面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 熱部署

如何能實現熱部署?

  1. 關於模板引擎

    • 在 Spring Boot 開發環境下禁用模板緩存
	#開發環境下關閉thymeleaf模板緩存,
 	spring.thymeleaf.cache=false
  1. 添加 Spring Boot Devtools 熱部署依賴
<!--熱部署-->
 <dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-devtools</artifactId>
 </dependency>
  1. 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默認基礎上,自動配置添加了以下特性:
    引入 ContentNegotiatingViewResolverBeanNameViewResolver beans.
  1. 自動配置了視圖解析器ViewResolver(根據方法返回值獲取視圖對象View,視圖對象決定如何渲染?重定向Or 轉發)
  2. 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。

    1. Converter :轉換器; 如: 文本類型轉換目標類型, true 轉 boolean類型
    2. GenericConverter :轉換器,Spring內部在註冊時,會將Converter先轉換爲GenericConverter之後,再統一對GenericConverter註冊。
    3. Formatter : 格式化器; 如: 2017/12/17 格式化 Date類型
  • 對 HttpMessageConverters 的支持。

  1. SpringMVC 用它來轉換Http請求和響應的;User _json User _xml
  2. 可以通過@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");
    }
}
  1. 自定義WebMvcConfigurer自動配置時會導入;
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
  2. EnableWebMvcConfiguration 繼承了 DelegatingWebMvcConfiguration
  3. 分析 DelegatingWebMvcConfiguration , 會將所有web配置組件加到WebMvcConfigurerComposite中
  4. 保留原來的配置類,也添加了新的配置類,所有的WebMvcConfigurer都會一起起作用
  5. 效果:SpringMVC的自動配置和我們的擴展配置都會起作用;

5.7 全面控制 SpringMVC

  • 如果你想全面控制SpringMVC(SpringBoot對SpringMVC的自動配置都廢棄), 在自定義的Web配置類上添加@Configuration 和 @EnableWebMvc 註解。

爲什麼添加了@EnableWebMvc SpringMVC的自動配置都廢棄了

  1. @EnableWebMvc
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
  1. 先記住繼承了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
  1. ErrorPageCustomizer 錯誤頁面定製器
  2. BasicErrorController 就會接收 /error 請求處理。
  3. DefaultErrorViewResolver 去解析具體響應的錯誤頁面。
  4. 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 ,有來匹配對應類型的所有錯誤
  • 採用精確優先
  • 錯誤頁面可獲取的的數據信息
    1. timestamp:時間戳
    2. status:狀態碼
    3. error:錯誤提示
    4. exception:異常對象
    5. message:異常消息
    6. 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來註冊三大組件:
  1. ServletRegistrationBean :註冊自定義Servlet
  2. FilterRegistrationBean :註冊自定義Filter
  3. 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容器提供以下支持
  1. Tomcat(默認使用)
  2. Jetty :支持長連接項目(如:聊天頁面)
  3. 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容器

  1. 必須創建一個 war 類型項目
  2. idea 上指定web.xml 與 修改好目錄結構
    1. 指定webapp目錄
    2. 指定web.xml位置
    3. 添加外置tomcat
  3. 在 pom.xml 將嵌入式的Tomcat指定爲provided (Spring初始化器已經默認指定了)
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-tomcat</artifactId>
	<scope>provided</scope>
</dependency>
  1. Spring初始化器 自動創建了 SpringBootServletInitializer 的子類,調用 configure 方法
  2. 直接開發項目功能即可, 然後啓動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 中;

  • 常見錯誤
  1. 需要配置文件中指定時區: jdbc:mysql://127.0.0.1:3306/jdbc?serverTimezone=GMT%2B8
  2. 警告: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 連接池與監控管理

  1. 引入依賴
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.12</version>
</dependency>
  1. 全局配置
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
  1. 自定義配置類, 將配置中屬性與 DruidDataSource 屬性綁定
  2. 配置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值

  1. @CacheConfig(cacheNames = “user”)
  2. @Cacheable(/cacheNames = “user”,/ key = “#id”)
  3. @CachePut(/cacheNames = “user”,/ key = “#user.id”)
  4. @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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章