1. 程式人生 > >App後臺開發運維和架構實踐學習總結(10)——基於Java-JWT前後端token認證實戰使用詳解

App後臺開發運維和架構實踐學習總結(10)——基於Java-JWT前後端token認證實戰使用詳解

一、什麼是JWT?瞭解JWT,認知JWT
首先jwt其實是三個英語單詞JSON Web Token的縮寫。通過全名你可能就有一個基本的認知了。token一般都是用來認證的,比如我們系統中常用的使用者登入token可以用來認證該使用者是否登入。jwt也是經常作為一種安全的token使用。
JWT的定義:JWT是一種用於雙方之間傳遞安全資訊的簡潔的、URL安全的表述性宣告規範。JWT作為一個開放的標準(RFC 7519),定義了一種簡潔的,自包含的方法用於通訊雙方之間以Json物件的形式安全的傳遞資訊。因為數字簽名的存在,這些資訊是可信的,JWT可以使用HMAC演算法或者是RSA的公私祕鑰對進行簽名。

JWT特點:簡潔(Compact): 可以通過URL,POST引數或者在HTTP header傳送,因為資料量小,傳輸速度也很快。自包含(Self-contained):負載中包含了所有使用者所需要的資訊,避免了多次查詢資料庫
二、JWT構成或者說JWT是什麼樣的?
2.1.JWT結構
JWT主要包含三個部分之間用英語句號'.'隔開
Header 頭部
Payload 負載
Signature 簽名
注意,順序是 header.payload.signature
最終的結構有點像這樣:
leftso.com.blog
當然真實的jwt不可能是這麼簡單的明文
2.2.JWT的頭部(Header)
在header中通常包含了兩部分:token型別和採用的加密演算法。如下:

{
  "alg": "HS256",
  "typ": "JWT"
}  
上面的JSON內容指定了當前採用的加密方式為HS256,token的型別為jwt
將上面的內容進行base64編碼,可以得到我們JWT的頭部,編碼後如下:
(本站提供了線上的base64編碼/解碼的工具,可供讀者測試)
ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9ICA=
2.3.JWT的負載(Payload)
負載(Payload)為JWT的第二部分。JWT的標準所定義了一下幾個基本欄位
iss: 該JWT的簽發者
sub: 該JWT所面向的使用者
aud: 接收該JWT的一方
exp(expires): 什麼時候過期,這裡是一個Unix時間戳

iat(issued at): 在什麼時候簽發的
除了標準定義的欄位外,我們還要定義一些我們在業務處理中需要用到的欄位,例如使用者token一般可以包含使用者登入的token或者使用者的id,一個簡單的例子如下:
{
    "iss": "Lefto.com",
    "iat": 1500218077,
    "exp": 1500218077,
    "aud": "www.leftso.com",
    "sub": "[email protected]",
    "user_id": "dc2c4eefe2d141490b6ca612e252f92e",
    "user_token": "09f7f25cdb003699cee05759e7934fb2"
}
上面的user_id、user_token都是我們自己定義的欄位
現在我們需要將負載這整個部分進行base64編碼,編碼後結果如下:
ewogICAgImlzcyI6ICJMZWZ0by5jb20iLAogICAgImlhdCI6IDE1MDAyMTgwNzcsCiAgICAiZXhwIjogMTUwMDIxODA3NywKICAgICJhdWQiOiAid3d3LmxlZnRzby5jb20iLAogICAgInN1YiI6ICJsZWZ0c29AcXEuY29tIiwKICAgICJ1c2VyX2lkIjogImRjMmM0ZWVmZTJkMTQxNDkwYjZjYTYxMmUyNTJmOTJlIiwKICAgICJ1c2VyX3Rva2VuIjogIjA5ZjdmMjVjZGIwMDM2OTljZWUwNTc1OWU3OTM0ZmIyIgp9
2.4.Signature(簽名)
簽名其實是對JWT的頭部和負載整合的一個簽名驗證
首先需要將頭部和負載通過.連結起來就像這樣:header.Payload,上述的例子連結起來之後就是這樣的:
ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9ICA=.ewogICAgImlzcyI6ICJMZWZ0by5jb20iLAogICAgImlhdCI6IDE1MDAyMTgwNzcsCiAgICAiZXhwIjogMTUwMDIxODA3NywKICAgICJhdWQiOiAid3d3LmxlZnRzby5jb20iLAogICAgInN1YiI6ICJsZWZ0c29AcXEuY29tIiwKICAgICJ1c2VyX2lkIjogImRjMmM0ZWVmZTJkMTQxNDkwYjZjYTYxMmUyNTJmOTJlIiwKICAgICJ1c2VyX3Rva2VuIjogIjA5ZjdmMjVjZGIwMDM2OTljZWUwNTc1OWU3OTM0ZmIyIgp9
由於HMacSHA256加密演算法需要一個key,我們這裡key暫時用leftso吧
加密後的內容為:
686855c578362e762248f22e2cc1213dc7a6aff8ebda52247780eb6b5ae91877
其實加密的內容也就是JWT的簽名,類似我們對某個檔案進行MD5加密然後接收到檔案進行md5對比一樣.只是這裡的HMacSHA256演算法需要一個key,當然這個key應該是使用者和接收者都知道的。
對上面的簽名內容進行base64編碼得到最終的簽名
Njg2ODU1YzU3ODM2MmU3NjIyNDhmMjJlMmNjMTIxM2RjN2E2YWZmOGViZGE1MjI0Nzc4MGViNmI1YWU5MTg3Nw==
2.5最終的JWT
ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9ICA=.ewogICAgImlzcyI6ICJMZWZ0by5jb20iLAogICAgImlhdCI6IDE1MDAyMTgwNzcsCiAgICAiZXhwIjogMTUwMDIxODA3NywKICAgICJhdWQiOiAid3d3LmxlZnRzby5jb20iLAogICAgInN1YiI6ICJsZWZ0c29AcXEuY29tIiwKICAgICJ1c2VyX2lkIjogImRjMmM0ZWVmZTJkMTQxNDkwYjZjYTYxMmUyNTJmOTJlIiwKICAgICJ1c2VyX3Rva2VuIjogIjA5ZjdmMjVjZGIwMDM2OTljZWUwNTc1OWU3OTM0ZmIyIgp9.Njg2ODU1YzU3ODM2MmU3NjIyNDhmMjJlMmNjMTIxM2RjN2E2YWZmOGViZGE1MjI0Nzc4MGViNmI1YWU5MTg3Nw==
通過上面的一個簡單的說明您是否對JWT有一個簡單額認知了呢?接下來我將講解JWT在Java程式設計中的使用
三、Java程式設計中jwt框架選擇
在Java程式設計中,實現jwt標準的有很多框架,本部落格採用的框架是auth0的java-jwt版本為3.2.0
四、什麼是Java-JWT
auth0的java-jwt是一個JSON WEB TOKEN(JWT)的一個實現。
五、安裝下載相關依賴
如果你是採用maven的方式,在你的專案pom.xml檔案中新增以下java-jwt的依賴片段:
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.2.0</version>
</dependency>
如果你是採用Gradle的方式,則新增以下內容:
compile 'com.auth0:java-jwt:3.2.0'
5.1、java-jwt已經實現的演算法
該庫使用以下演算法實現JWT驗證和簽名:
JWS演算法介紹
HS256HMAC256HMAC with SHA-256
HS384HMAC384HMAC with SHA-384
HS512HMAC512HMAC with SHA-512
RS256RSA256RSASSA-PKCS1-v1_5 with SHA-256
RS384RSA384RSASSA-PKCS1-v1_5 with SHA-384
RS512RSA512RSASSA-PKCS1-v1_5 with SHA-512
ES256ECDSA256ECDSA with curve P-256 and SHA-256
ES384ECDSA384ECDSA with curve P-384 and SHA-384
ES512ECDSA512ECDSA with curve P-521 and SHA-512
六、如何使用java-jwt
6.1.選擇一種演算法
  演算法定義了一個令牌是如何被簽名和驗證的。它可以用HMAC演算法的原始值來例項化,也可以在RSA和ECDSA演算法的情況下對金鑰對或金鑰提供程式進行例項化。建立後,該例項可用於令牌簽名和驗證操作。
在使用RSA或ECDSA演算法時,只需要簽署JWTs,就可以通過傳遞null值來避免指定公鑰。當您需要驗證JWTs時,也可以使用私鑰進行操作
使用靜態的字元密文或者key來獲取演算法器:
 //HMAC
Algorithm algorithmHS = Algorithm.HMAC256("secret");
//RSA
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);
使用一個key提供者來獲取演算法:
  通過使用KeyProvider,您可以在執行時更改金鑰,用於驗證令牌簽名或為RSA或ECDSA演算法簽署一個新的令牌。這是通過實現RSAKeyProvider或ECDSAKeyProvider方法實現的:
getPublicKeyById(String kid): 它在令牌簽名驗證中呼叫,它應該返回用於驗證令牌的金鑰。如果使用了關鍵的輪換,例如JWK,它可以使用id來獲取正確的輪換鍵(或者只是一直返回相同的鍵)。
getPrivateKey(): 在令牌簽名期間呼叫它,它應該返回用於簽署JWT的金鑰。
getPrivateKeyId():在令牌簽名期間呼叫它,它應該返回標識由getPrivateKey()返回的鍵的id的id。這個值比JWTCreator.Builder和keyid(String)方法中的值更受歡迎。如果您不需要設定孩子的值,就避免使用KeyProvider例項化演算法。
下面的程式碼片段將展示如何使用:
final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}");
final RSAPrivateKey privateKey = //Get the key instance
final String privateKeyId = //Create an Id for the above key
RSAKeyProvider keyProvider = new RSAKeyProvider() {
    @Override
    public RSAPublicKey getPublicKeyById(String kid) {
        //Received 'kid' value might be null if it wasn't defined in the Token's header
        RSAPublicKey publicKey = jwkStore.get(kid);
        return (RSAPublicKey) publicKey;
    }


    @Override
    public RSAPrivateKey getPrivateKey() {
        return privateKey;
    }


    @Override
    public String getPrivateKeyId() {
        return privateKeyId;
    }
};
Algorithm algorithm = Algorithm.RSA256(keyProvider);
//Use the Algorithm to create and verify JWTs.
提示:對於使用JWKs的簡單的鍵輪換,可以嘗試JWKs-rsa-java庫。
6.2.建立一個簽名的JWT token
首先需要通過呼叫jwt.create()建立一個JWTCreator例項
例如使用 HS256演算法:
try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    String token = JWT.create()
        .withIssuer("auth0")
        .sign(algorithm);
} catch (UnsupportedEncodingException exception){
    //UTF-8 encoding not supported
} catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
}
例如使用RS256演算法:
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
try {
    Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
    String token = JWT.create()
        .withIssuer("auth0")
        .sign(algorithm);
} catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
}
如果Claim不能轉換為JSON,或者在簽名過程中使用的金鑰無效,那麼將會丟擲JWTCreationException異常。
6.3.驗證令牌
  首先需要通過呼叫jwt.require()和傳遞演算法例項來建立一個JWTVerifier例項。如果您要求令牌具有特定的Claim值,請使用構建器來定義它們。方法build()返回的例項是可重用的,因此您可以定義一次,並使用它來驗證不同的標記。最後呼叫verifier.verify()來驗證token
例如使用 HS256演算法的時候:
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    JWTVerifier verifier = JWT.require(algorithm)
        .withIssuer("auth0")
        .build(); //Reusable verifier instance
    DecodedJWT jwt = verifier.verify(token);
} catch (UnsupportedEncodingException exception){
    //UTF-8 encoding not supported
} catch (JWTVerificationException exception){
    //Invalid signature/claims
}
例如使用 RS256演算法的時候:
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
try {
    Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
    JWTVerifier verifier = JWT.require(algorithm)
        .withIssuer("auth0")
        .build(); //Reusable verifier instance
    DecodedJWT jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
    //Invalid signature/claims
}
如果令牌有一個無效的簽名,或者沒有滿足Claim要求,那麼將會丟擲JWTVerificationException異常
6.4.jwt時間的驗證
JWT令牌可能包括可用於驗證的DateNumber欄位:
這個令牌釋出了一個過期的時間 "iat" < TODAY
這個令牌還沒過期 "exp" > TODAY and
這個令牌已經被使用了. "nbf" > TODAY
當驗證一個令牌時,時間驗證會自動發生,導致在值無效時丟擲一個JWTVerificationException。如果前面的任何一個欄位都丟失了,那麼在這個驗證中就不會考慮這些欄位。
要指定令牌仍然被認為有效的餘地視窗,在JWTVerifier builder中使用accept迴旋()方法,並傳遞一個正值的秒值。這適用於上面列出的每一項。
JWTVerifier verifier = JWT.require(algorithm)
    .acceptLeeway(1) // 1 sec for nbf, iat and exp
    .build();
您還可以為給定的日期宣告指定一個自定義值,併為該宣告覆蓋預設值。
JWTVerifier verifier = JWT.require(algorithm)
    .acceptLeeway(1)   //1 sec for nbf and iat
    .acceptExpiresAt(5)   //5 secs for exp
    .build();
如果您需要在您的lib/app中測試此行為,將驗證例項轉換為basever視覺化,以獲得verific.build()方法的可見性,該方法可以接受定製的時鐘。例如:
BaseVerification verification = (BaseVerification) JWT.require(algorithm)
    .acceptLeeway(1)
    .acceptExpiresAt(5);
Clock clock = new CustomClock(); //Must implement Clock interface
JWTVerifier verifier = verification.build(clock);
6.5解碼一個jwt令牌
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
try {
    DecodedJWT jwt = JWT.decode(token);
} catch (JWTDecodeException exception){
    //Invalid token
}
如果令牌有無效的語法,或者訊息頭或有效負載不是JSONs,那麼將會丟擲JWTDecodeException異常。
6.6JWT頭部解析
Algorithm ("alg")
返回jwt的演算法值或,如果沒有定義則返回null
String algorithm = jwt.getAlgorithm();
Type ("typ")
返回jwt的型別值,如果沒有定義則返回null(多數情況型別值為jwt)
String type = jwt.getType();
Content Type ("cty")
返回內容的型別,如果沒有定義則返回null
String contentType = jwt.getContentType();
Key Id ("kid")
返回key的id值,如果沒有定義則返回null
String keyId = jwt.getKeyId();
私有的Claims,即自定義欄位
在令牌的頭部中定義的附加宣告可以通過呼叫getHeaderClaim() 獲取,即使無法找到,也會返回。您可以通過呼叫claim.isNull()來檢查宣告的值是否為null。
Claim claim = jwt.getHeaderClaim("owner");
當使用jwt.create()建立一個令牌時,您可以通過呼叫withHeader()來指定頭宣告,並同時傳遞宣告的對映。
Map<String, Object> headerClaims = new HashMap();
headerClaims.put("owner", "auth0");
String token = JWT.create()
        .withHeader(headerClaims)
        .sign(algorithm);
提示:在簽名過程之後,alg和typ值將始終包含在Header中。


6.7JWT的負載(Payload)宣告
Issuer ("iss")
返回簽發者的名稱值,如果沒有在負載中定義則返回null
String issuer = jwt.getIssuer();
Subject ("sub")
返回jwt所面向的使用者的值,如果沒有在負載中定義則返回null
String subject = jwt.getSubject();
Audience ("aud")
返回該jwt由誰接收,如果沒有在負載中定義則返回null
List<String> audience = jwt.getAudience();
Expiration Time ("exp")
返回該jwt的過期時間,如果在負載中沒有定義則返回null
Date expiresAt = jwt.getExpiresAt();
Not Before ("nbf")
Returns the Not Before value or null if it's not defined in the Payload.
Date notBefore = jwt.getNotBefore();
Issued At ("iat")
返回在什麼時候簽發的,如果在負載中沒有定義則返回null
Date issuedAt = jwt.getIssuedAt();
JWT ID ("jti")
返回該jwt的唯一標誌,如果在負載中沒有定義則返回null
String id = jwt.getId();
自定義宣告
在令牌有效負載中定義的附加宣告可以通過呼叫getClaims()或 getClaim()和傳遞宣告名來獲得。即使無法找到宣告,也將會有返回值。您可以通過呼叫claim.isNull()來檢查宣告的值是否為null。
Map<String, Claim> claims = jwt.getClaims();    //Key is the Claim name
Claim claim = claims.get("isAdmin");
或者:
Claim claim = jwt.getClaim("isAdmin");
當使用jwt.create()建立一個令牌時,您可以通過呼叫withClaim()來指定自定義宣告,並同時傳遞名稱和值。
String token = JWT.create()
        .withClaim("name", 123)
        .withArrayClaim("array", new Integer[]{1, 2, 3})
        .sign(algorithm);
您還可以通過呼叫withClaim()來驗證jwt.require()的自定義宣告,並傳遞該名稱和所需的值。
JWTVerifier verifier = JWT.require(algorithm)
    .withClaim("name", 123)
    .withArrayClaim("array", 1, 2, 3)
    .build();
DecodedJWT jwt = verifier.verify("my.jwt.token");
提示:當前支援的自定義JWT宣告建立和驗證的型別是:Boolean, Integer, Double, String, Date 和Arrays。
6.8Claim Class
索賠類是索賠值的包裝器。它允許您將索賠作為不同的類型別。可用的工具方法:
原始的:
asBoolean(): 返回布林值,如果不能轉換返回null。
asInt(): 返回整數值,如果不能轉換返回null。
asDouble(): 返回 Double 值,如果不能轉換則返回null。
asLong(): 返回Long 值,如果不能轉換則返回null。
asString(): 返回String值,如果不能轉換則返回null。
asDate(): 返回 Date值,如果不能轉換則返回null。 必須是一個數字日期 (Unix 系統時間戳). 注意,JWT標準指定所有的數字日期值必須以秒為單位。
自定義型別和集合:
要獲得作為集合的宣告,您需要提供要轉換的內容的類型別
as(class): 返回 Class Type 的解析值. 對於集合,您應該使用asArray和asList方法。
asMap(): 返回被轉換為 Map<String, Object>的值
asArray(class): 返回被轉換成元素型別的 Class Type, or null if the value isn't a JSON Array.
asList(class): 返回集合元素的 Class Type, or null if the value isn't a JSON Array.
如果不能將值轉換為給定的類型別,則會丟擲JWTDecodeException異常

相關推薦

App後臺發運維和架構實踐學習總結10——基於Java-JWT前後token認證實戰使用

一、什麼是JWT?瞭解JWT,認知JWT首先jwt其實是三個英語單詞JSON Web Token的縮寫。通過全名你可能就有一個基本的認知了。token一般都是用來認證的,比如我們系統中常用的使用者登入token可以用來認證該使用者是否登入。jwt也是經常作為一種安全的token使用。JWT的定義:JWT是一種

App後臺發運維和架構實踐學習總結6——App客戶後臺互動方式總結

1、HTTP簡單基本認證方式 這個是早期互動用得比較多的一種方式,主要是使用使用者名稱和密碼來互動,由於在每次的互動中,使用者名稱和密碼都會暴露給第三方,那麼這麼做是不可取的,風險十分大,所以這種

App後臺發運維和架構實踐讀書筆記

App後臺開發運維和架構實踐 App後臺基礎技術 從App業務邏輯中提煉API介面 業務邏輯思維導圖 功能 - 業務邏輯思維導圖 基本功能模組關係 人有哪些功能模組 事有哪些功能模組 人和事之間的關係又有哪些模組 *

專案管理學習總結9——史上最全網際網路八大技術崗位

網際網路技術崗位詳解,涉及到前段開發、後端開發、移動端開發、大資料、專案管理、測試、運維、技術管理等八大領域。架構師每個產品線都有架構師,在技術平臺部門也需要技術平臺的架構師。架構師負責設計系統整體架構,從需求到設計的每個細節都要考慮到,把握整個專案,使設計的專案儘量效率高,

TMS320C6474學習總結----DSP/BIOS自帶例程 mailbox exampe

附上例程的主程式: #include <std.h> #include <log.h> #include <mbx.h> #include <tsk.h> #include "mailboxcfg.h" #defi

Maven學習總結27——Maven自定義打包外掛maven-assembly-plugin

Assembly外掛會生成 “assemblies”, 此特性等同於的Maven 1 distribution plug-in.。該外掛不僅支援建立二進位制歸檔檔案,也支援建立原始碼歸檔檔案。這些as

軟件架構設計學習總結13:大型網站技術架構網站的可擴展性架構

開放 擴展 修改 restfu 消息發送 封裝 nts 進行 可擴展性 擴展性是指對現有系統影響最小的情況下,系統功能可持續擴展或提升的能力。 設計網站可擴展架構的核心思想是模塊化,並在此基礎上,降低模塊間的耦合性,提供模塊的復用性。模塊通過分布式部署,獨立

軟件架構設計學習總結14:大型網站技術架構網站的安全架構

根據 知情 提交 pac 請求參數 用途 text 避免 信息加密 從互聯網誕生起,安全威脅就一直伴隨著網站的發展,各種Web攻擊和信息泄露也從未停止。常見的攻擊手段有XSS攻擊、SQL註入、CSRF、Session劫持等。 1、XSS攻擊 XSS攻擊即跨站點腳本攻擊(C

軟件架構設計學習總結12:大型網站技術架構網站的伸縮性架構

可用性 name 偶數 發送 得到 合並 linux vi 可謂 性能 網站系統的伸縮性架構最重要的技術手段就是使用服務器集群功能,通過不斷地向集群中添加服務器來增強整個集群的處理能力。“伸”即網站的規模和服務器的規模總是在不斷擴大。 1、網站架構的伸縮性設計 網站的伸縮性

軟件架構設計學習總結23:軟件架構設計的6大原則

str 軟件架構 edge 程序員 難點 posit not 幫我 mman 1. 單一職責原則(Single Responsibility Principle - SRP) 原文:There should never be more than one reason fo

Java學習總結十三——基於UDP協議網絡編程

網絡編程 UDP協議 聊天 一.UDP網絡編程1.面向無連接的數據傳輸,不可靠的,但效率高(音頻,視頻等).2.UDP一次發送的數據不能超過64kb.3.UDP編程所需要的類(1)DatagramSocket此類表示用來發送和接收數據報包的套接字(2)DatagramPacket此類表示數據報包方

java基礎學習總結十三Java異常處理

一、JAVA異常       異常是指不期而至的各種情況,如:檔案找不到、網路連線失敗、非法引數等。異常是一個事件,它發生在程式執行期間,干擾了正常的指令流程。Java通過API中的Throwable類的眾多子類描述各種不同的異常。因而,Java異常都是物件,是Th

java基礎學習總結Java中的反射

Native      JDK開放給使用者的原始碼中隨處可見Native方法,被Native關鍵字宣告的方法說明該方法不是以Java語言實現的,而是以本地語言實現的,Java可以直接拿來用。這裡有一個概念,就是本地語言,本地語言這四個字,個人理解應該就是可以和作業系

MyBatis學習總結---基於XML多表聯合查詢一對一、一對多、多對多

1、一對一的關聯  使用association,association元素用於處理“has-one”(一對一)這種型別關係。  作用:針對pojo物件屬性的對映,它的兩個主要引數此時對應的值: javaType對應pojo類名,  property對應pojo的

Redis學習總結10——快取雪崩、快取穿透、快取併發、快取預熱、快取演算法的概念及解決思路總結

一、快取雪崩 概念: 可能是因為資料未載入到快取中,或者快取同一時間大面積的失效,從而導致所有請求都去查資料庫,導致資料庫CPU和記憶體負載過高,甚至宕機。 解決思路: 1.1、加鎖計數(即限制併發的數量,可以用semphore)或者起一定數量的佇列來避免快取失效時大

Spring學習66基於java類,Groovy,編碼的方式對Bean進行配置

Spring學習6(6) 基於Java類的配置 使用Java類提供Bean的定義資訊  普通的PoJo只要標註了@Configuration註解就可以為Spring容器提供Bean的定義資訊,每個標註了@Bean的方法都相當於提供了一個Bean的定義資訊程式碼如

Servlet學習總結10監聽器

監聽器概念         Servlet監聽器是Servlet規範中定義的一種特殊類,用於監聽ServletContext、HttpSession和ServletRequest等域物件的建立與銷燬事件,以及監聽這些域物件中屬性發生修改的事件。 監聽物件: Servle

Spring Boot學習總結10——SpringBoot打包成Docker映象

<build><!--定義jar檔名,可以自定義--><finalName>${project.name}-${project.version}</finalN

敏捷開發系列學習總結10——到底什麼是敏捷開發?

1,提要 軟體開發是一個系統工程,包括最初的可行性分析、再到設計、開發、測試、維護等整個生命週期。在這個過程中某些階段的失誤或說是變化,都可能增加整個軟體專案的風險。 如何在保證效率的基礎上還能安計劃

Docker學習總結10——10分鐘玩轉Docker

1、前言 進入雲端計算的時代,各大雲提供商AWS,阿里雲紛紛推出針對Docker的服務,現在Docker是十分火爆,那麼Docker到底是什麼,讓我們來體驗一下。 2、Docker是什麼 Dock