springboot在我看來是spring的進階版,之前想應該不是太難,誰知裏面對於spring的註解應用的出神入化,所以springbooot第一次學習之後腦子裏空空一片,然後決定再來學習一邊,終於算是摸到了springboot的門檻。
pom
啓動器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
@SpringBootApplication
public class SpringbootResulfcrudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootResulfcrudApplication.class, args);
}
}
註解:
@ComponentScan //掃描當前啓動類同級的包
@SpringBootApplication // springboot的啓動入口註解
@SpringBootConfiguration //springboot的設定
@Configuration //spring中的註解,代表這是一個設定類
@Component //說明這是一個spring的元件
@EnableAutoConfiguration //springboot的自動設定
@AutoConfigurationPackage //自動設定包
@Import({Registrar.class}) //自動設定「包註冊」
@Import({AutoConfigurationImportSelector.class}) //自動設定選擇
@ComponentScan //掃描當前啓動類同級的包
//獲取所有的設定
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
獲取候選的設定
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
SpringBoot使用一個全域性的組態檔,組態檔名是固定的;
application.properties
application.yml
組態檔的作用:修改SpringBoot自動設定的預設值;SpringBoot在底層都給我們自動設定好;
YAML(YAML Ain’t Markup Language)
標示語言:
YAML:設定例子
server:
port: 8081
<server>
<port>8081</port>
</server>
k:(空格)v:表示一對鍵值對(空格必須有);
以空格的縮排來控制層級關係;只要是左對齊的一列數據,都是同一個層級的
server:
port: 8081
context-path: /hello
屬性和值也是大小寫敏感;
k: v:字面直接來寫;
字串預設不用加上單引號或者雙引號;
「」:雙引號;不會跳脫字串裏面的特殊字元;特殊字元會作爲本身想表示的意思
name: 「zhangsan \n lisi」:輸出;zhangsan 換行 lisi
‘’:單引號;會跳脫特殊字元,特殊字元最終只是一個普通的字串數據
name: ‘zhangsan \n lisi’:輸出;zhangsan \n lisi
k: v:在下一行來+
寫物件的屬性和值的關係;注意縮排
物件還是k: v的方式
friends:
lastName: zhangsan
age: 20
行內寫法:
friends: {lastName: zhangsan,age: 18}
用- 值表示陣列中的一個元素
pets:
- cat
- dog
- pig
行內寫法
pets: [cat,dog,pig]
組態檔
person:
lastName: hello
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1,k2: 12}
lists:
- lisi
- zhaoliu
dog:
name: 小狗
age: 12
javaBean:
/**
* 將組態檔中設定的每一個屬性的值,對映到這個元件中
* @ConfigurationProperties:告訴SpringBoot將本類中的所有屬性和組態檔中相關的設定進行系結;
* prefix = "person":組態檔中哪個下面 下麪的所有屬性進行一一對映
*
* 只有這個元件是容器中的元件,才能 纔能容器提供的@ConfigurationProperties功能;
*
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
我們可以匯入組態檔處理器,以後編寫設定就有提示了
<!--匯入組態檔處理器,組態檔進行系結就會有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
調整
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批次注入組態檔中的屬性 | 一個個指定 |
鬆散系結(鬆散語法) | 支援 | 不支援 |
SpEL | 不支援 | 支援 |
JSR303數據校驗 | 支援 | 不支援 |
複雜型別封裝 | 支援 | 不支援 |
組態檔yml還是properties他們都能獲取到值;
如果說,我們只是在某個業務邏輯中需要獲取一下組態檔中的某項值,使用@Value;
如果說,我們專門編寫了一個javaBean來和組態檔進行對映,我們就直接使用@ConfigurationProperties;
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}從環境變數、組態檔中獲取值/#{SpEL}"></property>
* <bean/>
*/
//lastName必須是郵箱格式
@Email
//@Value("${person.last-name}")
private String lastName;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
@PropertySource:載入指定的組態檔;
/**
* 將組態檔中設定的每一個屬性的值,對映到這個元件中
* @ConfigurationProperties:告訴SpringBoot將本類中的所有屬性和組態檔中相關的設定進行系結;
* prefix = "person":組態檔中哪個下面 下麪的所有屬性進行一一對映
*
* 只有這個元件是容器中的元件,才能 纔能容器提供的@ConfigurationProperties功能;
* @ConfigurationProperties(prefix = "person")預設從全域性組態檔中獲取值;
*
*/
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
//@Validated
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}從環境變數、組態檔中獲取值/#{SpEL}"></property>
* <bean/>
*/
//lastName必須是郵箱格式
// @Email
//@Value("${person.last-name}")
private String lastName;
//@Value("#{11*2}")
private Integer age;
//@Value("true")
private Boolean boss;
@ImportResource:匯入Spring的組態檔,讓組態檔裏面的內容生效;
Spring Boot裏面沒有Spring的組態檔,我們自己編寫的組態檔,也不能自動識別;
想讓Spring的組態檔生效,載入進來;@ImportResource標註在一個設定類上
@ImportResource(locations = {"classpath:beans.xml"})
匯入Spring的組態檔讓其生效
不來編寫Spring的組態檔
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloService" class="com.atguigu.springboot.service.HelloService"></bean>
</beans>
SpringBoot推薦給容器中新增元件的方式;推薦使用全註解的方式
1、設定類**@Configuration**------>Spring組態檔
2、使用**@Bean**給容器中新增元件
/**
* @Configuration:指明當前類是一個設定類;就是來替代之前的Spring組態檔
*
* 在組態檔中用<bean><bean/>標籤新增元件
*
*/
@Configuration
public class MyAppConfig {
//將方法的返回值新增到容器中;容器中這個元件預設的id就是方法名
@Bean
public HelloService helloService02(){
System.out.println("設定類@Bean給容器中新增元件了...");
return new HelloService();
}
}
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
person.last-name=張三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog
person.dog.age=15
我們在主組態檔編寫的時候,檔名可以是 application-{profile}.properties/yml
預設使用application.properties的設定;
server:
port: 8081
spring:
profiles:
active: prod
---
server:
port: 8083
spring:
profiles: dev
---
server:
port: 8084
spring:
profiles: prod #指定屬於哪個環境
1、在組態檔中指定 spring.profiles.active=dev
2、命令列:
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
可以直接在測試的時候,設定傳入命令列參數
3、虛擬機器參數;
-Dspring.profiles.active=dev
springboot 啓動會掃描以下位置的application.properties或者application.yml檔案作爲Spring boot的預設組態檔
–file:./config/
–file:./
–classpath:/config/
–classpath:/
優先順序由高到底,高優先順序的設定會覆蓋低優先順序的設定;
SpringBoot會從這四個位置全部載入主組態檔;互補設定;
我們還可以通過spring.config.location來改變預設的組態檔位置
專案打包好以後,我們可以使用命令列參數的形式,啓動專案的時候來指定組態檔的新位置;指定組態檔和預設載入的這些組態檔共同起作用形成互補設定;
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
SpringBoot也可以從以下位置載入設定; 優先順序從高到低;高優先順序的設定覆蓋低優先順序的設定,所有的設定會形成互補設定
1.命令列參數
所有的設定都可以在命令列上進行指定
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
多個設定用空格分開; --設定項=值
2.來自java:comp/env的JNDI屬性
3.Java系統屬性(System.getProperties())
4.操作系統環境變數
5.RandomValuePropertySource設定的random.*屬性值
由jar包外向jar包內進行尋找;
優先載入帶profile
6.jar包外部的application-{profile}.properties或application.yml(帶spring.profile)組態檔
7.jar包內部的application-{profile}.properties或application.yml(帶spring.profile)組態檔
再來載入不帶profile
8.jar包外部的application.properties或application.yml(不帶spring.profile)組態檔
9.jar包內部的application.properties或application.yml(不帶spring.profile)組態檔
10.@Configuration註解類上的@PropertySource
11.通過SpringApplication.setDefaultProperties指定的預設屬性
所有支援的設定載入來源
@Value這個使用起來並不友好!我們需要爲每個屬性單獨註解賦值,比較麻煩;我們來看個功能對比圖
1、@ConfigurationProperties只需要寫一次即可 , @Value則需要每個欄位都新增
2、鬆散系結:這個什麼意思呢? 比如我的yml中寫的last-name,這個和lastName是一樣的, - 後面跟着的字母預設是大寫的。這就是鬆散系結。可以測試一下
3、JSR303數據校驗 , 這個就是我們可以在欄位是增加一層過濾器驗證 , 可以保證數據的合法性
4、複雜型別封裝,yml中可以封裝物件 , 使用value就不支援
結論:
設定yml和設定properties都可以獲取到值 , 強烈推薦 yml;
如果我們在某個業務中,只需要獲取組態檔中的某個值,可以使用一下 @value;
如果說,我們專門編寫了一個JavaBean來和組態檔進行一一對映,就直接使用@configurationProperties。
JSP、Velocity、Freemarker、Thymeleaf
SpringBoot推薦的Thymeleaf;語法更簡單,功能更強大;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
2.1.6
</dependency>
切換thymeleaf版本
<properties>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!-- 佈局功能的支援程式 thymeleaf3主程式 layout2以上版本 -->
<!-- thymeleaf2 layout1-->
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
//
只要我們把HTML頁面放在classpath:/templates/,thymeleaf就能自動渲染;
使用:
1、匯入thymeleaf的名稱空間
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2、使用thymeleaf語法;
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>成功!</h1>
<!--th:text 將div裏面的文字內容設定爲 -->
<div th:text="${hello}">這是顯示歡迎資訊</div>
</body>
</html>
1)、th:text;改變當前元素裏面的文字內容;
th:任意html屬性;來替換原生屬性的值
Simple expressions:(表達式語法)
Variable Expressions: ${...}:獲取變數值;OGNL;
1)、獲取物件的屬性、呼叫方法
2)、使用內建的基本物件:
#ctx : the context object.
#vars: the context variables.
#locale : the context locale.
#request : (only in Web Contexts) the HttpServletRequest object.
#response : (only in Web Contexts) the HttpServletResponse object.
#session : (only in Web Contexts) the HttpSession object.
#servletContext : (only in Web Contexts) the ServletContext object.
${session.foo}
3)、內建的一些工具物件:
#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris : methods for escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
Selection Variable Expressions: *{...}:選擇表達式:和${}在功能上是一樣;
補充:配合 th:object="${session.user}:
<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
Message Expressions: #{...}:獲取國際化內容
Link URL Expressions: @{...}:定義URL;
@{/order/process(execId=${execId},execType='FAST')}
Fragment Expressions: ~{...}:片段參照表達式
<div th:insert="~{commons :: main}">...</div>
Literals(字面量)
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations:(文字操作)
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations:(數學運算)
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Boolean operations:(布爾運算)
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality:(比較運算)
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators:條件運算(三元運算子)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens:
No-Operation: _
ContentNegotiatingViewResolver
和BeanNameViewResolver
beans。Converter
,GenericConverter
和Formatter
beans。HttpMessageConverters
( 本文件稍後部分)。MessageCodesResolver
( 本文件後面部分)。index.html
支援。Favicon
支援(本文件稍後介紹)。ConfigurableWebBindingInitializer
bean(本文 後面會介紹)。如果你想保留Spring Boot MVC功能,並且你想新增額外的 MVC設定(攔截器,格式化程式,檢視控制器和其他功能),你可以新增自己的@Configuration類WebMvcConfigurer類但沒有 @EnableWebMvc。如果您希望提供RequestMappingHandlerMapping,RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定義範例,則可以宣告WebMvcRegistrationsAdapter範例以提供此類元件。
如果您想完全控制Spring MVC,可以新增自己的@Configuration註釋@EnableWebMvc。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.servlet.config.annotation;
import java.util.List;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {
}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
//格式化
default void addFormatters(FormatterRegistry registry) {
}
//攔截器
default void addInterceptors(InterceptorRegistry registry) {
}
//靜態資源過濾
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
default void addCorsMappings(CorsRegistry registry) {
}
//檢視控制
default void addViewControllers(ViewControllerRegistry registry) {
}
//檢視解析器
default void configureViewResolvers(ViewResolverRegistry registry) {
}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
package com.atyldy.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
/**
* @author shkstart
* @create 2020-08-02 23:05
*/
@Configurable
public class MyMvcConfig implements WebMvcConfigurer {
/**
* 註冊元件
* ViewResolver s實現了檢視解析器類的介面,在這裏就可以把它看作檢視解析器
* @return
*/
@Bean
public ViewResolver MyConfigViewResolve(){
return new MyViewResolve();
}
/**
* 自定義一個檢視解析器的類
*/
public static class MyViewResolve implements ViewResolver{
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
}
package com.atyldy.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
/**
* @author shkstart
* @create 2020-08-02 23:05
*/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
/**
* 檢視控制
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login.html").setViewName("index");
registry.addViewController("/").setViewName("index");
}
}
在application.properties中指定國際化檔案路徑
# 指定國際化檔案的路徑
spring.messages.basename=i18n.login
[外連圖片轉存失敗,源站可能有防盜鏈機制 機製,建議將圖片儲存下來直接上傳(img-vfDugAiD-1597138558221)(D:\NULL\學習資源\md筆記\images\sprtingboot國際化.png)]
在html頁面獲取國際化訊息
<-- Message Expressions: #{...}:獲取國際化內容-->
<label>
<input type="checkbox" > [[#{login.remember}]]
</label>
設定參數,實現國際化
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
java程式碼實現中英文切換
LocaleResolver介面中solveLocale(HttpServletRequest request)的方法是定製國際化的方法,自定義國際化需要實現LocaleResolver介面,重寫solveLocale(HttpServletRequest request)方法
package com.atyldy.config;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* @author shkstart
* @create 2020-08-08 18:01
*/
public class MyLocaleResolver implements LocaleResolver {
// 解析請求
@Override
public Locale resolveLocale(HttpServletRequest request) {
// 獲取國際化連線參數l
String language = request.getParameter("l");
// 設定預設國際化方法,如果沒有就是用預設值
Locale locale = Locale.getDefault();
// 判斷參數是否爲空
if (!StringUtils.isEmpty(language)) {
// 分割參數
String[] split = language.split("_");
// 國家,地區
locale=new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
自定義攔截器,繼承HandlerInterceptor介面,實現preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 方法
package com.atyldy.config;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author shkstart
* @create 2020-08-09 7:19
*/
public class MyInterceptors implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 獲取session,判斷使用者是否登錄
Object loginUsername = request.getSession().getAttribute("loginUsername");
// 判斷是否獲取到了session的值,若爲空則不放行
if (loginUsername==null){
request.setAttribute("msg","許可權不足,請重新登錄!");
// 請求轉發
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else {
return true;
}
}
}
加入到擴充套件Mvc中
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptors()) //加入自定義攔截器
.addPathPatterns("/**")// 需要攔截
.excludePathPatterns("/index.html","/user/login","login.html","/","/css/*","/js/*","/img/*");
//不需要攔截
}
提取公共頁面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>公共部分</title>
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/dashboard.css}" rel="stylesheet">
</head>
<body>
<!--頭部
th:fragment="bartip
-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="bartip">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUsername}]]</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" th:href="@{/user/logout}">註銷</a>
</li>
</ul>
</nav>
<!--側邊欄
th:fragment="sidebar"
-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a th:class="${active=='main.html'?'nav-link active':'nav-link'}" th:href="@{/main.html}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
Dashboard <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/main.html}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
<polyline points="13 2 13 9 20 9"></polyline>
</svg>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shopping-cart">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
Products
</a>
</li>
<li class="nav-item">
<a th:class="${active=='emps'?'nav-link active':'nav-link'}" th:href="@{/emps}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
員工管理
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart-2">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-layers">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
Integrations
</a>
</li>
</ul>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Saved reports</span>
<a class="d-flex align-items-center text-muted" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
</a>
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Current month
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Last quarter
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Social engagement
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Year-end sale
</a>
</li>
</ul>
</div>
</nav>
</body>
</html>
使用公共部分
<!--頭部
th:replace:替換
th:inset:插入
-->
<div th:replace="~{comons/comons::bartip}"></div>
<!-- 側邊欄-->
<div th:replace="~{comons/comons::sidebar(active='emps')}"></div>
轉換日期格式
<!--
#dates.format():轉換日期格式
-->
<td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm')}"></td>
定製錯誤頁面
1、在templates資料夾下新建error資料夾
2、在error資料夾裡新建404.html或500.html、5xxx.html,springboot會自動識別