## 簡介
Java 8中的時區操作被很大程度上簡化了,新的時區類 `java.time.ZoneId` 是原有的 `java.util.TimeZone` 類的替代品。
ZoneId對象可以通過 `ZoneId.of()` 方法創建,也可以通過 `ZoneId.systemDefault()` 獲取系統默認時區:
```java
ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai");
ZoneId systemZoneId = ZoneId.systemDefault();
```
`of()` 方法接收一個“區域/城市”的字符串作為參數,你可以通過 `getAvailableZoneIds()` 方法獲取所有合法的“區域/城市”字符串:
```java
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
```
對于老的時區類 `TimeZone`,Java 8也提供了轉化方法:
```java
ZoneId oldToNewZoneId = TimeZone.getDefault().toZoneId();
```
有了 `ZoneId`,我們就可以將一個 `LocalDate`、`LocalTime` 或 `LocalDateTime` 對象轉化為 `ZonedDateTime` 對象:
```java
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, shanghaiZoneId);
```
`ZonedDateTime` 對象由兩部分構成,`LocalDateTime` 和 `ZoneId`,其中 `2018-03-03T15:26:56.147` 部分為 `LocalDateTime`,`+08:00[Asia/Shanghai]` 部分為ZoneId。
另一種表示時區的方式是使用 `ZoneOffset`,它是以當前時間和 **世界標準時間(UTC)/格林威治時間(GMT)** 的偏差來計算,例如:
```java
ZoneOffset zoneOffset = ZoneOffset.of("+09:00");
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime, zoneOffset);
```
## Instant
Instant類在Java日期與時間功能中,表示了時間線上一個確切的點,定義為距離初始時間的時間差(初始時間為GMT 1970年1月1日00:00)經測量一天有86400秒,從初始時間開始不斷向前移動。
**創建一個Instant實例**
你可以通過Instant類的工廠方法創建一個Instant實例,例如你可以調用instant.now()來創建一個確切的表達當前時間的Instant對象:
```java
Instant now = Instant.now();
```
另外也有一些其它方法能創建Instant,具體請查閱Java官方文檔。
**訪問Instant的時間**
一個Instant對象里有兩個域:距離初始時間的秒鐘數、在當前一秒內的第幾納秒,他們的組合表達了當前時間點。你可以通過以下兩個方法得到它們的值:
```java
long seconds = getEpochSecond()
int nanos = getNano()
```
**Instant的計算**
Instant類有一些方法,可以用于獲得另一Instant的值,例如:
- `plusSeconds()`
- `plusMillis()`
- `plusNanos()`
- `minusSeconds()`
- `minusMillis()`
- `minusNanos()`
我下面將向你展示兩個例子,來說明這些方法如何使用:
```java
Instant now = Instant.now();
Instant later = now.plusSeconds(3);
Instant earlier = now.minusSeconds(3);
```
第一行獲得了一個Instant對象,表示當前時間。第二行創建了一個Instant表示三秒后,第三行創建了一個Instant表示三秒前。
> seconds 表示從 `1970-01-01 00:00:00` 開始到現在的秒數,nanos 表示納秒部分(nanos的值不會超過999,999,999)
## Clock
Clock類提供了訪問當前日期和時間的方法,Clock是時區敏感的,可以用來取代 `System.currentTimeMillis()` 來獲取當前的微秒數。
某一個特定的時間點也可以使用Instant類來表示,Instant 類也可以用來創建老的 `java.util.Date` 對象。
```java
Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
Instant instant = clock.instant();
Date legacyDate = Date.from(instant); // legacy java.util.Date
```
## LocalDate
LocalDate類是Java 8中日期時間功能里表示一個本地日期的類,它的日期是無時區屬性的。
可以用來表示生日、節假日期等等。這個類用于表示一個確切的日期,而不是這個日期所在的時間(如java.util.Date中的2000.01.01表示的實際是這一天的00:00這個瞬間)。
LocalDate類位于java.time包下,人名叫java.time.LocalDate,創建出來的實例也是不可變對象,所以涉及它的計算方法將返回一個新的LocalDate。
**創建一個LocalDate實例**
我們有多種方式可以創建出 `LocalDate` 實例。第一種方法是使用 `now()` 方法獲得值為今天當日的 `LocalDate` 對象:
```java
LocalDate localDate = LocalDate.now();
```
另一種方法是使用年月日信息構造出LocalDate對象:
```java
LocalDate localDate2 = LocalDate.of(2018, 3, 3);
```
LocalDate 的 `of()` 方法創建出一個指定年月日的日期,并且沒有時區信息。
**訪問日期信息**
可以用如下方法訪問LocalDate中的日期信息:
```java
int year = localDate.getYear();
Month month = localDate.getMonth();
int dayOfMonth = localDate.getDayOfMonth();
int dayOfYear = localDate.getDayOfYear();
DayOfWeek dayOfWeek = localDate.getDayOfWeek();
```
可以注意到getMonth()與getDayOfWeek()方法返回了一個枚舉類型代替一個int。你可以通過枚舉類型中的getValue()來獲得信息。
**LocalDate計算**
你可以進行一堆簡單的日期計算,只要使用如下的方法:
- `plusDays()`
- `plusWeeks()`
- `plusMonths()`
- `plusYears()`
- `minusDays()`
- `minusWeeks()`
- `minusMonths()`
- `minusYears()`
以下舉幾個使用的例子來幫助理解使用:
```java
LocalDate d = LocalDate.of(2018, 3, 5);
LocalDate d1 = localDate.plusYears(3);
LocalDate d2 = localDate.minusYears(3);
```
1. 第一行創建出一個新的LocalDate對象d,表示2018.3.5。
2. 第二行創建了值等于d日期3年后的LocalDate對象,第三行也是一樣,只是值改為d日期的三年前。
## LocalTime
LocalTime類是Java 8中日期時間功能里表示一整天中某個時間點的類,它的時間是無時區屬性的(早上10點等等)。比如你需要描述學校幾點開學,這個時間不涉及在什么城市,這個描述是對任何國家城市都適用的,此時使用無時區的LocalTime就足夠了。
LocalTime類的對象也是不可變的,所以計算方法會返回一個新的LocalTime實例。
**創建一個LocatTime實例**
有多種方式可以新建LocalTime實例。比如使用當前時間作為值新建對象:
```java
LocalTime localTime = LocalTime.now();
```
另一種方式是使用指定的時分秒和納秒來新建對象:
```java
LocalTime localTime2 = LocalTime.of(21, 30, 59, 11001);
```
也有另一種版本的 `of()` 方法只需要小時分鐘兩項,或時分秒三項值作為參數。
**訪問LocalTime對象的時間**
你可以通過這些方法訪問其時、分、秒、納秒:
- `getHour()`
- `getMinute()`
- `getSecond()`
- `getNano()`
**LocalTime的計算**
LocalTime類包含一系列方法,能幫你完成時間計算:
- `plusHours()`
- `plusMinutes()`
- `plusSeconds()`
- `plusNanos()`
- `minusHours()`
- `minusMinutes()`
- `minusSeconds()`
- `minusNanos()`
以下舉一個例子:
```java
LocalTime localTime2 = LocalTime.of(21, 30, 59, 11001);
LocalTime localTimeLater = localTime.plusHours(3);
LocalTime localTimeEarlier = localTime.minusHours(3);
```
1. 第一行新建一個LocalTime實例,表示21:30:50的第11001納秒。
2. 第二行新建了一個LocalTime實例表示這個時間的三小時后,第三行表示三小時前。
3. LocalTime類是Java 8中日期時間功能里表示一整天中某個時間點的類,它的時間是無時區屬性的(早上10點等等)。比如你需要描述學校幾點開學,這個時間不涉及在什么城市,這個描述是對任何國家城市都適用的,此時使用無時區的LocalTime就足夠了。
LocalTime類的對象也是不可變的,所以計算方法會返回一個新的LocalTime實例。
## LocalDateTime
LocalDateTime類是Java 8中日期時間功能里,用于表示當地的日期與時間的類,它的值是無時區屬性的。你可以將其視為Java 8中LocalDate與LocalTime兩個類的結合。
LocalDateTime類的值是不可變的,所以其計算方法會返回一個新的LocalDateTime實例。
**創建一個LocatDateTime實例**
可以通過LocalDateTime的靜態工廠方法來創建LocalDateTime實例。以下舉例使用 `now()` 方法創建:
```java
LocalDateTime localDateTime = LocalDateTime.now();
```
另一種方式是使用指定的年月日、時分秒、納秒來新建對象:
```java
LocalDateTime localDateTime2 = LocalDateTime.of(2018, 11, 26, 13, 55, 36, 123);
```
**訪問LocalDateTime對象的時間**
你可以通過這些方法訪問其日期時間:
- `getYear()`
- `getMonth()`
- `getDayOfMonth()`
- `getDayOfWeek()`
- `getDayOfYear()`
- `getHour()`
- `getMinute()`
- `getSecond()`
- `getNano()`
這些方法中有一些返回int有一些返回枚舉類型,你可以通過枚舉類型中的 `getValue()` 方法來獲得int值。
**LocalDateTime的計算**
LocalDateTime 類包含一系列方法,能幫你完成時間計算:
- `plusYears()`
- `plusMonths()`
- `plusDays()`
- `plusHours()`
- `plusMinutes()`
- `plusSeconds()`
- `plusNanos()`
- `minusYears()`
- `minusMonths()`
- `minusDays()`
- `minusHours()`
- `minusMinutes()`
- `minusSeconds()`
- `minusNanos()`
以下舉一個例子:
```java
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime localDateTime1 = localDateTime.plusYears(3);
LocalDateTime localDateTime2 = localDateTime.minusYears(3);
```
1. 第一行新建一個LocalDateTime實例表示當前這個時間。
2. 第二行新建了一個LocalDateTime實例表示三年后。
3. 第三行也新建了一個LocalDateTime實例表示三小時前。
## ZonedDateTime
ZonedDateTime類是Java 8中日期時間功能里,用于表示帶時區的日期與時間信息的類。可以用于表示一個真實事件的開始時間,如某火箭升空時間等等。
ZonedDateTime 類的值是不可變的,所以其計算方法會返回一個新的ZonedDateTime 實例。
**創建一個ZonedDateTime實例**
有多種方式可以新建ZonedDateTime實例。比如使用當前時間作為值新建對象:
```java
ZonedDateTime dateTime = ZonedDateTime.now();
```
另一種方式是使用指定的年月日、時分秒、納秒以及時區ID來新建對象:
```java
ZoneId zoneId = ZoneId.of("UTC+1");
ZonedDateTime dateTime2 = ZonedDateTime.of(2015, 11, 30, 23, 45, 59, 1234, zoneId);
```
**訪問ZonedDateTime對象的時間**
你可以通過這些方法訪問其日期時間:
- `getYear()`
- `getMonth()`
- `getDayOfMonth()`
- `getDayOfWeek()`
- `getDayOfYear()`
- `getHour()`
- `getMinute()`
- `getSecond()`
- `getNano()`
這些方法中有一些返回int有一些返回枚舉類型,但可以通過枚舉類型中的getValue()方法來獲得int值。
**ZonedDateTime的計算**
ZonedDateTime類包含一系列方法,能幫你完成時間計算:
- `plusYears()`
- `plusMonths()`
- `plusDays()`
- `plusHours()`
- `plusMinutes()`
- `plusSeconds()`
- `plusNanos()`
- `minusYears()`
- `minusMonths()`
- `minusDays()`
- `minusHours()`
- `minusMinutes()`
- `minusSeconds()`
- `minusNanos()`
但注意計算時,若不巧跨越了夏令時(會補一小時或減一小時),可能得不到希望的結果。一個替代的正確做法是使用Period:
```java
ZonedDateTime zoneDateTime = previousDateTime.plus(Period.ofDays(3));
```
**時區**
時區是用ZoneId類表示的,你可以使用ZoneId.now()或ZoneId.of(“xxx”)來實例化:
```java
ZoneId zoneId = ZoneId.of("UTC+1");
```
傳給 `of()` 方法的參數是時區的ID,如“UTC+1”指距離UTC(格林威治時間)有一小時的時差,你可以使用你想要的時差來表示ZoneId(如+1與-5等等)
你也可以使用另一種方式表示zone id,即使用地區名字,也是可以的:
```java
ZoneId zoneId2 = ZoneId.of("Europe/Copenhagen");
ZoneId zoneId3 = ZoneId.of("Europe/Paris");
```
## DateTimeFormatter
DateTimeFormatter類是Java 8中日期時間功能里,用于解析和格式化日期時間的類,位于 `java.time.format` 包下。
**預定義的DateTimeFormatter實例**
DateTimeFormatter類包含一系列預定義(常量)的實例,可以解析和格式化一些標準時間格式。這將讓你免除麻煩的時間格式定義,類中包含如下預定義的實例:
```java
BASIC_ISO_DATE
ISO_LOCAL_DATE
ISO_LOCAL_TIME
ISO_LOCAL_DATE_TIME
ISO_OFFSET_DATE
ISO_OFFSET_TIME
ISO_OFFSET_DATE_TIME
ISO_ZONED_DATE_TIME
ISO_INSTANT
ISO_DATE
ISO_TIME
ISO_DATE_TIME
ISO_ORDINAL_TIME
ISO_WEEK_DATE
RFC_1123_DATE_TIME
```
每個預定義的DateTimeFormatter實例都有不同的日期格式,我就不解釋全部的了。具體的可以查閱Java官方文檔,但我在這篇的后續中會解釋其中幾個,以方便理解。
**格式化日期**
當你獲取一個DateTimeFormatter實例后,就可以用format()方便來將一個日期格式化為某種字符串,例如:
```java
DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
String formattedDate = formatter.format(LocalDate.now());
System.out.println(formattedDate);
```
這個樣例把LocalDate對象格式化了,并輸出20150703,這個輸出表示現在2018年,3月5日。
再舉一個關于ZonedDateTime的例子:
```java
DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
String formattedZonedDate = formatter.format(ZonedDateTime.now());
System.out.println("formattedZonedDate = " + formattedZonedDate);
```
這個例子會輸出:20180305+0800
表示今年2018年,3月5日,位于UTC+8時區。
## Duration
一個Duration對象表示兩個Instant間的一段時間,是在Java 8中加入的新功能。
一個Duration實例是不可變的,當創建出對象后就不能改變它的值了。你只能通過Duration的計算方法,來創建出一個新的Durtaion對象。你會在之后的教程中見到的。
**創建Duration實例**
使用 `Duration` 類的工廠方法來創建一個 `Duration` 對象,以下是一個使用 `between()` 的例子:
```java
Instant first = Instant.now();
// wait some time while something happens
Instant second = Instant.now();
Duration duration = Duration.between(first, second);
```
**訪問Duration的時間**
一個Duration對象里有兩個域:納秒值(小于一秒的部分),秒鐘值(一共有幾秒),他們的組合表達了時間長度。注意屯使用System.getCurrentTimeMillis()時不同,Duration不包含毫秒這個屬性。
你可以通過以下兩個方法得到它們的值:
```java
long seconds = getSeconds()
int nanos = getNano()
```
你也可以轉換整個時間到其它單位如納秒、分鐘、小時、天:
- `toNanos()`
- `toMillis()`
- `toMinutes()`
- `toHours()`
- `toDays()`
舉例而言:`toNanos()` 與 `getNano()` 不同,`toNanos()` 獲得的是 `Duration` 整個時間共有多少納秒,
而 `getNano()` 只是獲得這段時間中小于一秒的部分。
你也許會問,為什么沒有 `toSeconds()` 方法,因為已經有 `getSeconds()` 這個方法能達到同樣的功能了。
**Duration計算**
Duration類包含一系列的計算方法:
- `plusNanos()`
- `plusMillis()`
- `plusSeconds()`
- `plusMinutes()`
- `plusHours()`
- `plusDays()`
- `minusNanos()`
- `minusMillis()`
- `minusSeconds()`
- `minusMinutes()`
- `minusHours()`
- `minusDays()`
這些方法所做的事都是相似的,我在這兒也不展示內部實現細節了,就展示一個加減的例子吧:
```java
Duration start = ... //obtain a start duration
Duration added = start.plusDays(3);
Duration subtracted = start.minusDays(3);
```
1. 第一行創建了一個Duration對象叫start,具體怎么創建可以參考前面的代碼。
2. 第二三行樣例創建了兩個新的Duration,通過調用start的加減操作,使得added對象表示的時間比start多三天,而substracted則少三天。
所有的計算方法都會返回一個新的Duration,以保證Duration的不可變屬性。
```java
long days = duration.toDays(); // 這段時間的總天數
long hours = duration.toHours(); // 這段時間的小時數
long minutes = duration.toMinutes(); // 這段時間的分鐘數
long seconds = duration.getSeconds(); // 這段時間的秒數
long milliSeconds = duration.toMillis(); // 這段時間的毫秒數
long nanoSeconds = duration.toNanos(); // 這段時間的納秒數
```
## 其他操作
### 增加和減少日期
Java 8中的日期/時間類都是不可變的,這是為了保證線程安全。當然,新的日期/時間類也提供了方法用于創建對象的可變版本,比如增加一天或者減少一天:
```java
LocalDate date = LocalDate.of(2017, 1, 5); // 2017-01-05
LocalDate date1 = date.withYear(2016); // 修改為 2016-01-05
LocalDate date2 = date.withMonth(2); // 修改為 2017-02-05
LocalDate date3 = date.withDayOfMonth(1); // 修改為 2017-01-01
LocalDate date4 = date.plusYears(1); // 增加一年 2018-01-05
LocalDate date5 = date.minusMonths(2); // 減少兩個月 2016-11-05
LocalDate date6 = date.plus(5, ChronoUnit.DAYS); // 增加5天 2017-01-10
```
上面例子中對于日期的操作比較簡單,但是有些時候我們要面臨更復雜的時間操作,比如將時間調到下一個工作日,
或者是下個月的最后一天,這時候我們可以使用 `with()` 方法的另一個重載方法,它接收一個TemporalAdjuster參數,
可以使我們更加靈活的調整日期:
```java
LocalDate date7 = date.with(nextOrSame(DayOfWeek.SUNDAY)); // 返回下一個距離當前時間最近的星期日
LocalDate date9 = date.with(lastInMonth(DayOfWeek.SATURDAY)); // 返回本月最后一個星期六
```
要使上面的代碼正確編譯,你需要使用靜態導入 `TemporalAdjusters` 對象:
`import static java.time.temporal.TemporalAdjusters.*;`
`TemporalAdjusters` 類中包含了很多靜態方法可以直接使用,下面的表格列出了一些方法:
| 方法名 | 描述 |
|:-----:|:-------|
| `dayOfWeekInMonth` | 返回同一個月中每周的第幾天 |
| `firstDayOfMonth` | 返回當月的第一天 |
| `firstDayOfNextMonth` | 返回下月的第一天 |
| `firstDayOfNextYear` | 返回下一年的第一天 |
| `firstDayOfYear` | 返回本年的第一天 |
| `firstInMonth` | 返回同一個月中第一個星期幾 |
| `lastDayOfMonth` | 返回當月的最后一天 |
| `lastDayOfNextMonth` | 返回下月的最后一天 |
| `lastDayOfNextYear` | 返回下一年的最后一天 |
| `lastDayOfYear` | 返回本年的最后一天 |
| `lastInMonth` | 返回同一個月中最后一個星期幾 |
| `next / previous` | 返回后一個/前一個給定的星期幾 |
| `nextOrSame / previousOrSame` | 返回后一個/前一個給定的星期幾,如果這個值滿足條件,直接返回 |
如果上面表格中列出的方法不能滿足你的需求,你還可以創建自定義的 `TemporalAdjuster` 接口的實現,
`TemporalAdjuster` 也是一個函數式接口,所以我們可以使用Lambda表達式:
```java
@FunctionalInterface
public interface TemporalAdjuster {
Temporal adjustInto(Temporal temporal);
}
```
比如給定一個日期,計算該日期的下一個工作日(不包括星期六和星期天):
```java
LocalDate date = LocalDate.of(2017, 1, 5);
date.with(temporal -> {
// 當前日期
DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
// 正常情況下,每次增加一天
int dayToAdd = 1;
// 如果是星期五,增加三天
if (dayOfWeek == DayOfWeek.FRIDAY) {
dayToAdd = 3;
}
// 如果是星期六,增加兩天
if (dayOfWeek == DayOfWeek.SATURDAY) {
dayToAdd = 2;
}
return temporal.plus(dayToAdd, ChronoUnit.DAYS);
});
```
### 其他歷法
Java中使用的歷法是ISO 8601日歷系統,它是世界民用歷法,也就是我們所說的公歷。平年有365天,閏年是366天。閏年的定義是:非世紀年,能被4整除;世紀年能被400整除。為了計算的一致性,公元1年的前一年被當做公元0年,以此類推。
此外Java 8還提供了4套其他歷法(很奇怪為什么沒有漢族人使用的農歷),每套歷法都包含一個日期類,分別是:
- `ThaiBuddhistDate`:泰國佛教歷
- `MinguoDate`:中華民國歷
- `JapaneseDate`:日本歷
- `HijrahDate`:伊斯蘭歷
每個日期類都繼承 `ChronoLocalDate` 類,所以可以在不知道具體歷法的情況下也可以操作。不過這些歷法一般不常用,除非是有某些特殊需求情況下才會使用。
這些不同的歷法也可以用于向公歷轉換:
```java
LocalDate date = LocalDate.now();
JapaneseDate jpDate = JapaneseDate.from(date);
```
由于它們都繼承ChronoLocalDate類,所以在不知道具體歷法情況下,可以通過ChronoLocalDate類操作日期:
```java
Chronology jpChronology = Chronology.ofLocale(Locale.JAPANESE);
ChronoLocalDate jpChronoLocalDate = jpChronology.dateNow();
```
我們在開發過程中應該盡量避免使用 `ChronoLocalDate`,盡量用與歷法無關的方式操作時間,因為不同的歷法計算日期的方式不一樣,
比如開發者會在程序中做一些假設,假設一年中有12個月,如果是中國農歷中包含了閏月,一年有可能是13個月,
但開發者認為是12個月,多出來的一個月屬于明年的。
再比如假設年份是累加的,過了一年就在原來的年份上加一,但日本天皇在換代之后需要重新紀年,所以過了一年年份可能會從1開始計算。
在實際開發過程中建議使用 `LocalDate`,包括存儲、操作、業務規則的解讀;除非需要將程序的輸入或者輸出本地化,
這時可以使用 `ChronoLocalDate` 類。
### 資料
- [SimpleDateFormat的線程安全問題與解決方案](http://www.cnblogs.com/zemliu/p/3290585.html)
- [為什么SimpleDateFormat不是線程安全的?](http://blog.csdn.net/yiifaa/article/details/73499053)
- [Java獲取N天前,N天后的日期(如3天)](http://blog.csdn.net/liuwei0376/article/details/13620879)
- 第零章 序
- 序言
- 系統架構
- 視頻公開課
- 開源版介紹
- 商業版介紹
- 功能對比
- 答疑流程
- 第一章 快速開始
- 升級必看
- 環境要求
- 環境準備
- 基礎環境安裝
- Docker安裝基礎服務
- Nacos安裝
- Sentinel安裝
- 插件安裝
- 建數據庫
- 工程導入
- 導入Cloud版本
- 導入Nacos配置
- 導入Boot版本
- 工程運行
- 運行Cloud版本
- 運行Boot版本
- 工程測試
- 測試Cloud版本
- 測試Boot版本
- 第二章 技術基礎
- Java
- Lambda
- Lambda 受檢異常處理
- Stream 簡介
- Stream API 一覽
- Stream API (上)
- Stream API (下)
- Optional 干掉空指針
- 函數式接口
- 新的日期 API
- Lombok
- SpringMVC
- Swagger
- Mybatis
- Mybatis-Plus
- 開發規范
- 第三章 開發初探
- 新建微服務工程
- 第一個API
- API鑒權
- API響應結果
- Redis緩存
- 第一個CRUD
- 建表
- 建Entity
- 建Service和Mapper
- 新增 API
- 修改 API
- 刪除 API
- 查詢 API
- 單條數據
- 多條數據
- 分頁
- 微服務遠程調用
- 聲明式服務調用 Feign
- 熔斷機制 Hystrix
- 第四章 開發進階
- 聚合文檔
- 鑒權配置
- 跨域處理
- Xss防注入
- 自定義啟動器
- Secure安全框架
- Token認證簡介
- Token認證配置
- PreAuth注解配置
- Token認證實戰
- Token認證加密
- 日志系統
- 原理解析
- 功能調用
- Seata分布式事務
- 簡介
- 編譯包啟動
- 配置nacos對接
- docker啟動
- 對接微服務
- 代碼生成配置
- 前言
- 數據庫建表
- 代碼生成
- 前端配置
- 優化效果
- 第五章 功能特性
- SaaS多租戶
- 概念
- 數據隔離配置
- 線程環境自定義租戶ID
- 多終端令牌認證
- 概念
- 系統升級
- 使用
- 第三方系統登錄
- 概念說明
- 對接說明
- 對接準備
- 配置說明
- 操作流程
- 后記
- UReport2報表
- 報表簡介
- 對接配置
- 報表后記
- 接口報文加密
- 簡介
- 運行邏輯
- 對接準備
- 功能配置
- 接口測試
- 改造查詢
- 改造提交
- 改造刪除
- 動態數據權限
- 數據權限簡介
- 數據權限開發
- 純注解配置
- Web全自動配置
- 注解半自動配置
- 數據權限注意點
- 動態接口權限
- 樂觀鎖配置
- 統一服務登陸配置
- Skywalking追蹤監控
- Minio分布式對象存儲
- Boot版本對接至Cloud
- 第六章 生產部署
- windows部署
- linux部署
- jar部署
- docker部署
- java環境安裝
- mysql安裝
- docker安裝
- docker-compose安裝
- harbor安裝
- 部署步驟
- 寶塔部署
- 準備工作
- 安裝工作
- 部署準備
- 部署后端
- 部署前端
- 部署域名
- 結束工作
- k8s平臺部署
- 第七章 版本控制
- Git遠程分支合并
- Git地址更換
- 第八章 學習資料
- 第九章 FAQ
- 第十章 聯系我們