JWT學習總結

文章目錄

  • 前置知識
      • Authorization頭部和 Cookie
      • CRSF攻擊
  • JWT概念
  • JWT認證流程
  • 使用
      • Springboot整合JWT
      • JwtUtil
  • JWT案例
      • 控制器
      • JWT攔截器
      • 注冊攔截器
      • 結果
  • session VS Jwt

前置知識

Authorization頭部和 Cookie

Authorization 頭部和 Cookie 是 HTTP 協議中兩種不同的身份認證 / 信息傳遞機制.

  • Authorization 頭部
    是 HTTP 協議中專門用于傳遞認證信息的請求頭,通常格式為:

    Authorization: <認證方案> <憑證>
    

    常見的認證方案有 Bearer(用于 JWT、OAuth2.0 令牌)、Basic(基礎認證)等。
    核心用途:向服務器證明客戶端的身份(如 “我是已登錄的用戶 XXX”),僅在需要身份驗證的請求中使用。

  • Cookie
    是服務器通過 Set-Cookie 響應頭下發給客戶端的小型數據片段,客戶端(如瀏覽器)會在后續請求中自動附加到請求頭中發送給服務器。
    核心用途:不僅用于身份認證(如 Session ID),還可存儲其他狀態信息(如用戶偏好、購物車數據等),是客戶端與服務器之間維護 “狀態” 的主要方式。

  1. 自動性Cookie 由客戶端自動攜帶,Authorization 需手動設置,這是兩者最根本的區別,也導致了 CSRF 風險的差異。
  2. 安全性Cookie 有內置安全屬性(HttpOnly 等),Authorization 依賴令牌本身和傳輸層安全(HTTPS)。
  3. 靈活性Authorization 更適合跨域、長令牌場景,Cookie 適合傳統狀態維護和輕量數據存儲。

CRSF攻擊

  1. 用戶登錄目標網站 A:用戶在瀏覽器中登錄網站 A(如銀行網站),網站 A 驗證通過后,會在用戶的瀏覽器中生成并存儲身份憑證(通常是 Cookie),用于后續請求的身份識別。
  2. 攻擊者誘導用戶訪問惡意網站 B:用戶在未退出網站 A 的情況下,被誘導點擊了攻擊者精心構造的惡意鏈接(如郵件、聊天消息中的鏈接),訪問了攻擊者控制的網站 B。
  3. 惡意網站 B 發送偽造請求:網站 B 的頁面中包含一段代碼(如 JavaScript),會自動向網站 A 的服務器發送一個請求(如轉賬請求)。由于用戶的瀏覽器中仍保存著網站 A 的登錄 Cookie,這個請求會自動攜帶該 Cookie,讓網站 A 誤以為是用戶本人發起的操作。
  4. 網站 A 執行未授權操作:網站 A 驗證請求中的 Cookie 有效,且未對請求的來源進行嚴格校驗,從而執行了攻擊者偽造的操作(如轉賬給攻擊者的賬戶)。

CSRF 攻擊的關鍵條件

  • 用戶必須已登錄目標網站(即瀏覽器中存在有效的身份憑證,如 Cookie)。
  • 攻擊者必須誘導用戶在登錄狀態下訪問惡意網站
  • 目標網站未對請求的合法性進行嚴格校驗(如未驗證請求來源、未使用 CSRF Token 等防御機制)。****

JWT概念

  • 概念:

    Json web token (JWT), 是為了在網絡應用環境間傳遞聲明而執行的一種基于JSON的開放標準((RFC 7519).該token被設計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便于從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用于認證,也可被加密。

  • 構成:

    第一部分我們稱它為頭部(header),

    第二部分我們稱其為載荷(payload, 類似于飛機上承載的物品),

    第三部分是簽證(signature).

  • header

    jwt的頭部承載兩部分信息:

    • 聲明類型,這里是jwt
    • 聲明加密的算法 通常直接使用 HMAC SHA256
  • playload

    載荷就是存放有效信息的地方。這些有效信息包含三個部分

    • 標準中注冊的聲明
    • 公共的聲明
    • 私有的聲明

    標準中注冊的聲明 (建議但不強制使用) :

    • iss: jwt簽發者
    • sub: jwt所面向的用戶
    • aud: 接收jwt的一方
    • exp: jwt的過期時間,這個過期時間必須要大于簽發時間
    • nbf: 定義在什么時間之前,該jwt都是不可用的.
    • iat: jwt的簽發時間
    • jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。

    公共的聲明 : 公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.

    私有的聲明 : 私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。

  • signature

    jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:

    • header (base64后的)
    • payload (base64后的)
    • secret

    這個部分需要base64加密后的header和base64加密后的payload使用.連接組成的字符串,然后通過header中聲明的加密方式進行加鹽secret組合加密,然后就構成了jwt的第三部分。

    如對稱加密:

    # 偽代碼
    signature = HMAC-SHA256(key=secret,message=header_encoded + "." + payload_encoded
    )
    
  • 注意事項

    將這三部分用.連接成一個完整的字符串,構成了最終的jwt

    注意:secret是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用來進行jwt的簽發和jwt的驗證,所以,它就是你服務端的私鑰,**在任何場景都不應該流露出去。**一旦客戶端得知這個secret, 那就意味著客戶端是可以自我簽發jwt了。

JWT認證流程

在這里插入圖片描述

  1. 用戶登錄
    用戶提交用戶名和密碼 → 服務器驗證成功 → 服務器生成 JWT(包含用戶信息和簽名) → 返回 JWT 給客戶端。
  2. 客戶端存儲
    客戶端(如瀏覽器)將 JWT 存儲在 localStorageCookie 等中。
  3. 后續請求
    客戶端每次請求時,在請求頭中攜帶 JWT(如 Authorization: Bearer <token>) → 服務器驗證簽名有效性 → 解析用戶信息 → 處理請求并返回結果。

使用

Springboot整合JWT

  • JWT的引入:

    <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
    <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
    </dependency>
    

在這里插入圖片描述

  • 具體說明:

    • token是通過荷載Claims或playholder兩者之一構造的,兩者不能同時提供,否則compact()將報異常。

    • token構建是荷載一般必須兩個屬性:sub和exp

      • sub:即token中保存的必要信息。
      • exp:即token的過期時間,當token過了過期時間時,解析token時會拋出ExpiredJwtException異常。
    • 將token轉換成Claims的方法是:Jwts類中的如下方法完成。

       public static JwtParser parser() {return new DefaultJwtParser();}
      

      具體實現如下:

      public Claims getClaimsByToken(String token) throws ExpiredJwtException{if(null == token)return null;return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}
      
  • 解析token。

    • 解析過程:

      • 第一步:將token轉換成Claims對象
      • 第二步:通過Claims對象的getSubject()方法獲取token中保存的信息。
    • 將token轉換成Claims的方法是:Jwts類中的如下方法完成。

       public static JwtParser parser() {return new DefaultJwtParser();}
      
    • 具體實現如下:

      public Claims getClaimsByToken(String token) throws ExpiredJwtException{if(null == token)return null;return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}
      
    • 將token轉換成Claims過程中將拋出如下異常

      • UnsupportedJwtException:當token不是通過Claims對象構建的token時。
      • ExpiredJwtException:當token已過期時。
      • MalformedJwtException:當token不是有效的Claims對象構建的token時。
      • SignatureException:當token的Signature驗證失敗時。
      • IllegalArgumentException:當token為null或token是空字符串或token中只有空字符時。
    • 通過Claims的方法獲取token中保存的信息。

      • 具體實現如下:

        /*2.通過token獲取構建時的信息*/public String getUserNameFromToken(String token) throws Exception{Claims claims = getClaimsByToken(token);return claims.getSubject();}
        

JwtUtil

/*** JwtToken生成的工具類* JWT token的格式:header.payload.signature* header的格式(算法、token的類型):* {"alg": "HS512","typ": "JWT"}* payload的格式(用戶名、創建時間、生成時間):* {"sub":"wang","created":1489079981393,"exp":1489684781}* signature的生成算法:* HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)* Created on 2018/4/26.*/
@Component
@Getter
public class JwtTokenUtil {private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);private static final String CLAIM_KEY_USERNAME = "user_name";private static final String CLAIM_KEY_CREATED = "created";@Value("${jwt.secret}")private String secret;@Value("${jwt.expiration}")private Long expiration;@Value("${jwt.tokenHead}")private String tokenHead;/*** 根據負責生成JWT的token*/private String generateToken(Map<String, Object> claims) {return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.HS512, secret).compact();}/*** 從token中獲取JWT中的負載*/private Claims getClaimsFromToken(String token) {Claims claims = null;try {claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {LOGGER.info("JWT格式驗證失敗:{}", token);}return claims;}/*** 生成token的過期時間*/private Date generateExpirationDate() {return new Date(System.currentTimeMillis() + expiration * 1000);}/*** 解密:從token中獲取登錄用戶名(項目使用)*/public String getUserNameFromToken(String token) {String username;try {Claims claims = getClaimsFromToken(token);username = claims.get(CLAIM_KEY_USERNAME,String.class);} catch (Exception e) {username = null;}return username;}/*** 加密: 根據用戶名生成token(項目使用)*/public  String generateUserNameStr(String username) {Map<String, Object> claims = new HashMap<>();claims.put(CLAIM_KEY_USERNAME,username);claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}/*** 判斷token是否已經失效*/private boolean isTokenExpired(String token) {Date expiredDate = getExpiredDateFromToken(token);return expiredDate.before(new Date());}/*** 從token中獲取過期時間*/private Date getExpiredDateFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims.getExpiration();}/*** 當原來的token沒過期時是可以刷新的** @param oldToken 帶tokenHead的token*/public String refreshHeadToken(String oldToken) {if(StrUtil.isEmpty(oldToken)){return null;}String token = oldToken.substring(tokenHead.length());if(StrUtil.isEmpty(token)){return null;}//token校驗不通過Claims claims = getClaimsFromToken(token);if(claims==null){return null;}//如果token已經過期,不支持刷新if(isTokenExpired(token)){return null;}//如果token在30分鐘之內剛刷新過,返回原tokenif(tokenRefreshJustBefore(token,30*60)){return token;}else{claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}}/*** 判斷token在指定時間內是否剛剛刷新過* @param token 原token* @param time 指定時間(秒)*/private boolean tokenRefreshJustBefore(String token, int time) {Claims claims = getClaimsFromToken(token);Date created = claims.get(CLAIM_KEY_CREATED, Date.class);Date refreshDate = new Date();//刷新時間在創建時間的指定時間內if(refreshDate.after(created)&&refreshDate.before(DateUtil.offsetSecond(created,time))){return true;}return false;}// 驗證令牌有效性//沒有使用 Spring Security,就不需要依賴其提供的 UserDetails 類,也無需遵循它的用戶認證流程。// 此時驗證 JWT 令牌并獲取用戶信息的思路會更簡潔,核心是從 JWT 中解析出用戶標識(如用戶名、ID 等),// 再通過自己的業務邏輯驗證用戶合法性。public Boolean validateToken(String token) {// 解析令牌(自動驗證簽名和過期時間)Jwts.parser().setSigningKey(secret).parseClaimsJws(token);return true;}}

JWT案例

這里將在springboot中展示jwt,通過攔截器的方式。(只展示后端代碼,可以使用postman測試,如果token是本地存儲localStorage,會存到postman的相應地方,和瀏覽器一樣)

大體流程如下:

  1. 第一次登錄,傳入用戶名和密碼
  2. 數據庫檢驗用戶名和密碼是否正確,如果正確,根據用戶信息(這里使用用戶名)生成token。封裝token和其他信息返回給前端。
  3. 前端拿到token,并且存到本地客戶端(如localstorage)。以后每次發送請求都會在請求頭中帶上 Authorization: Bearer <token>
  4. 再次向服務端發送請求時就會經過Jwt的攔截器,拿到請求頭中的token,解析token是否合法,如果合法即可證明用戶身份并放行。

控制器

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JwtTokenUtil jwtTokenUtil;//簡單登錄接口@PostMapping("/login")public Result<LoginVO> login(@RequestBody LoginDTO loginDTO) {boolean auth = userService.authenticate(loginDTO);if (!auth){return Result.error(40101, "用戶名或密碼錯誤");}// 生成tokenString token = jwtTokenUtil.generateUserNameStr(loginDTO.getUsername());String authToken = "Bearer " + token;return Result.success(new LoginVO(loginDTO.getUsername(), authToken,jwtTokenUtil.getExpiration()*1000 + System.currentTimeMillis()));}//測試接口@GetMapping("/info")public Result<String> info() {return Result.success("info");}
}

JWT攔截器

public class JwtInceptor implements HandlerInterceptor {private final JwtTokenUtil jwtTokenUtil;public JwtInceptor(JwtTokenUtil jwtTokenUtil) {this.jwtTokenUtil = jwtTokenUtil;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//獲取請求頭中令牌String token = request.getHeader("Authorization");if(token != null && token.startsWith("Bearer ")){token = token.substring(7);//驗證令牌if(jwtTokenUtil.validateToken(token)){//驗證通過,放行,提取用戶信息病傳遞到后續處理String username = jwtTokenUtil.getUserNameFromToken(token);request.setAttribute("username",username);return true;}}//驗證失敗,返回401response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT");return false;}
}

注冊攔截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInceptor()).addPathPatterns("/**").excludePathPatterns("/user/login");}@Beanpublic JwtInceptor jwtInceptor() {return new JwtInceptor(jwtTokenUtil);}
}

結果

登錄:http://localhost:8080/user/login

{"code": 200,"msg": "操作成功","data": {"username": "saber","token": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX25hbWUiOiJzYWJlciIsImNyZWF0ZWQiOjE3NTEyNzE4NjY5NTEsImV4cCI6MTc1MTM1ODI2Nn0.TF2_XwhON3H-Jn_fdG5xacATxu_4lvJqY19C1JUCKkQjWYeW2vRdh5lwlgoCjw-nqTEPbJyRrC7Hg3TBOyuCjw","expireTime": 1751358267094}
}

測試:http://localhost:8080/user/info

{"code": 200,"msg": "操作成功","data": "info"
}

session VS Jwt

  1. 服務器存儲壓力大,擴展性差,有性能開銷:認證信息(用戶ID,權限等)存儲在服務器端(通常是內存中),客戶端通過session ID與服務器端關聯

    • 當用戶量激增時,服務器需要存儲大量的session,會占用大量的內存/存儲資源
    • 在分布式系統中(如多臺服務器負載均衡),需要保證session在多臺服務器間同步,復雜度高,維護成本大
    • 根據 Session ID 在內存中查找對應的 Session 對象,有性能開銷,如果存儲在redis或數據庫,性能開銷較高。
    • 如果存儲在內存中,重啟系統后用戶需要重新登錄,影響用戶體驗。
  2. 依賴cookie,存在安全風險:通常依賴 Cookie 傳遞 Session ID,而 Cookie 存在以下風險:

    • CSRF(跨站請求偽造):攻擊者可能利用用戶的 Cookie 在其他網站發起惡意請求(如轉賬),因為 Session ID 會隨 Cookie 自動發送。

    • Cookie 劫持:如果 Session ID 通過 HTTP 明文傳輸,可能被竊聽;即使使用 HTTPS,也可能通過 XSS 攻擊獲取 Cookie 中的 Session ID,進而偽造身份。

    • JWT 對比
      可通過 HTTP Header(如Authorization: Bearer <token>)傳遞,不依賴 Cookie,從根源上避免了 CSRF 風險。

      即使 Token 被存儲在 LocalStorage,雖仍可能面臨 XSS 攻擊,但可通過設置 Token 有效期較短、配合 HTTPS 等方式降低風險,且 JWT 的簽名機制能防止 Token 被篡改。

  3. 難以實現跨域認證

    • 傳統 Session
      由于 Cookie 的同源策略限制,跨域請求(如前后端分離架構中,前端域名與后端 API 域名不同)時,Session ID 可能無法正常傳遞(需額外配置CORS和 Cookie 跨域屬性),實現復雜且兼容性差。
    • JWT 對比
      基于 Header 傳遞的 JWT 不受同源策略限制,可輕松支持跨域認證(如不同域名的前端應用調用同一后端 API),只需在請求頭中攜帶 Token 即可,更適合前后端分離、微服務等分布式架構。
  4. Token 有效期管理靈活度低

    • Session

      Session 的有效期通常在服務器端設置(如 30 分鐘),若需提前失效 (如用戶登出、密碼修改、賬號異常),需在服務器端主動刪除對應的 Session 數據。服務端可控性強。

    • JWT

      無法修改已生成的token,其exp無法更新,但可以通過token的刷新機制,但短期 Token(如 15 分鐘)配合刷新 Token(Refresh Token)的機制,可兼顧安全性和用戶體驗,且無需服務器存儲全量認證數據。

場景JWT傳統 Session
分布式 / 微服務架構? 無狀態,無需共享 Session? 需要 Session 共享機制
跨域認證? 支持跨域(Header 傳遞)? 依賴 Cookie,需額外配置
移動端應用? 輕量,易于客戶端管理? 依賴 Cookie,移動端支持差
高并發場景? 驗證快(本地計算),無需 IO? 頻繁查詢存儲,性能瓶頸
安全性要求極高? Token 一旦泄露風險大? 服務端可控(如強制登出)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87318.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87318.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87318.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

阿里云消息隊列 Apache RocketMQ 創新論文入選頂會 ACM FSE 2025

近日&#xff0c;由阿里云消息團隊發表的 Apache RocketMQ 創新論文被 CCF-A 類軟件工程頂級會議 FSE 2025 Industry Track 錄用。 ACM FSE&#xff08;The ACM International Conference on the Foundations of Software Engineering&#xff09;是享有盛譽的國際學術會議&…

定制WordPress管理后臺

WordPress作為全球最流行的建站工具&#xff0c;因其靈活性和易用性受到廣泛歡迎。許多服務器提供商都支持一鍵安裝WordPress&#xff0c;例如Hostease&#xff0c;使新手用戶也能輕松搭建屬于自己的網站。然而&#xff0c;后臺的默認設置可能無法完全滿足不同用戶的需求。定制…

REST API設計與Swagger:構建高效、易用的Web服務

引言 在現代Web開發中&#xff0c;REST API已成為不同系統間通信的標準方式。一個設計良好的REST API不僅能提高開發效率&#xff0c;還能改善用戶體驗。而Swagger&#xff08;現稱為OpenAPI&#xff09;作為API文檔和測試的強大工具&#xff0c;已經成為API開發中不可或缺的一…

一個非對齊訪問的問題

1、引言 最近在編寫代碼時&#xff0c;出現了這樣一個 bug。程序一跑&#xff0c;系統就崩潰了&#xff0c;報錯是 bus error。 目標平臺&#xff1a;ARM32 最終定位到出錯的代碼片段&#xff1a; *((uint32_t *)ptr) id;這里的 ptr 是一個非 4 字節對齊的地址&#xff01;&a…

【構造】P8976 「DTOI-4」排列|普及+

本文涉及知識點 構造 P8976 「DTOI-4」排列 題目背景 Update on 2023.2.1&#xff1a;新增一組針對 yuanjiabao 的 Hack 數據&#xff0c;放置于 #21。 Update on 2023.2.2&#xff1a;新增一組針對 CourtesyWei 和 bizhidaojiaosha 的 Hack 數據&#xff0c;放置于 #22。…

多路I/O轉接服務器(select、poll、epoll)

多路IO轉接服務器也叫做多任務IO服務器。該類服務器實現的主旨思想是&#xff0c;不再由應用程序自己監視客戶端連接&#xff0c;取而代之由內核替應用程序監視文件。 IO 多路轉接方式比較&#xff1a; 常見的 IO 多路轉接方式有&#xff1a;select、poll、epoll&#xff0c;他…

最新臨時文件快傳系統源碼 輕量化 帶后臺

簡介&#xff1a; 最新臨時文件快傳系統源碼 輕量化 帶后臺 首發 輕松上傳文件并生成提取碼分享給他人&#xff0c;無需注冊&#xff0c;方便快捷。 圖片&#xff1a;

MyBatis多數據源動態連接工具類實現

這個DatabaseService工具類提供了動態創建MyBatis SqlSession的能力&#xff0c;可以靈活地連接到不同的數據庫&#xff0c;非常適合需要動態切換數據源的場景。 package com.cmes.immp.device.utils;import lombok.SneakyThrows; import org.apache.commons.dbcp2.BasicDataS…

用亮數據 MCP 驅動 Trae 智能體:打造高效亞馬遜商品采集與分析助手

本文適合希望快速構建數據驅動型智能體的開發者、數據工程師及 AI 產品設計者閱讀 并非廣告&#xff0c;希望本文可以幫助有需求的同學&#xff0c;祝大家天天開心 在數字時代&#xff0c;數據是決策與洞察趨勢的關鍵。但移動互聯網數據獲取不易&#xff0c;傳統爬蟲技術面對復…

如何降低AIGC生成內容的重復率?五種免費降AI率的方法 (25年更新)

隨著AI生成內容&#xff08;AIGC&#xff09;的普及&#xff0c;越來越多的學術寫作依賴AI工具來生成論文和文章。然而&#xff0c;AI生成內容的查重率常常偏高&#xff0c;導致很多論文無法通過學術查重系統。為了解決這一問題&#xff0c;以下是五種有效的免費降AIGC率的方法…

小米YU7使用UWB技術,厘米級定位精準迎賓,安全防破解無感控車

當您雙手抱著快遞走向愛車時&#xff0c;車門自動解鎖&#xff1b;當您站在前備箱前稍作停留&#xff0c;箱蓋優雅升起——這不是科幻電影&#xff0c;而是小米YU7搭載UWB技術帶來的真實體驗。在2025年5月的小米15周年戰略新品發布會上&#xff0c;雷軍揭曉了這項革命性技術&am…

WPF學習(動畫)

文章目錄 一、圖像變換 RenderTransform1、常見變換類型2、RenderTransform 的核心作用3、RenderTransform 的使用方式4、與 LayoutTransform 的對比5、在動畫中的應用 二、 滾動的橢圓三、Storyboard放置位置1. **元素的 Resources 集合**2. **控件模板&#xff08;ControlTem…

Crossbar結構的排隊策略

目錄 一、概述 二、排隊策略 三、輸入排隊結構(IQ) 3.1 結構特點 3.2 改進方案 四、輸出排隊結構&#xff08;OQ&#xff09; 五、輸入輸出聯合排隊結構(CIOQ) 六、輸入交叉節點聯合排隊結構(CICQ) 一、概述 Crossbar是一種全連接的交換結構&#xff0c;由 MN 個交叉…

狀態模式 - Flutter中的狀態變身術,讓對象隨“狀態“自由切換行為!

訂單狀態流轉/播放器控制/游戲角色行為…一個模式搞定所有狀態驅動型邏輯&#xff01; 經典場景&#xff1a;訂單狀態管理 假設你在開發一個外賣App&#xff0c;訂單有以下狀態&#xff1a; 等待接單已接單配送中已完成已取消 每個狀態下&#xff1a; 顯示的UI不同可執行的…

數據庫9:數據庫字符編碼調整與校隊(排序)規則

一.常用字符編碼 1.ASCII編碼 用一個字節表示一個字符 2.ANSI編碼 每個國家為了顯示本國的語言而對ASCII碼進行了拓展 用兩個字節表示一個漢字&#xff0c;中國的ANSI編碼是GB2312編碼&#xff08;簡體&#xff09;&#xff0c;日本的ANSI編碼是JIS編碼&#xff0c;臺灣的A…

人臉活體識別4:Android實現人臉眨眼 張嘴 點頭 搖頭識別(可實時檢測)

人臉活體識別4&#xff1a;Android實現人臉眨眼 張嘴 點頭 搖頭識別(可實時檢測) 目錄 人臉活體識別4&#xff1a;Android實現人臉眨眼 張嘴 點頭 搖頭識別(可實時檢測) 1. 前言 2.人臉活體識別方法 &#xff08;1&#xff09;基于人臉動作的檢測?? &#xff08;2&…

DAY1-Linux操作系統1

文章參考【黑馬程序員Python教程_600集Python從入門到精通教程&#xff08;懂中文就能學會&#xff09;】 https://www.bilibili.com/video/BV1ex411x7Em/?p40&share_sourcecopy_web&vd_source263bbee2ddeb835c3ab6d9d3c80e0f7c 一.常用命令簡單介紹 使用軟件 虛擬機…

第十二節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 - 兩種權限控制方式(附前后端代碼)

Vben5 系列文章目錄 ?? 基礎篇 ? 第一節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 ? 第二節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 - Python Flask 后端開發詳解(附源碼) ? 第三節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入…

華為云Flexus+DeepSeek征文 | 華為云 ModelArts Studio 賦能 AI 法務:合同審查與法律文件生成系統

一、引言 在法律行業數字化轉型的浪潮中&#xff0c;AI 技術正重塑法律服務的流程與效率。本文介紹如何利用華為云 ModelArts Studio 構建一套完整的 AI 法務系統&#xff0c;實現合同審查、法律文件生成、法律咨詢與風險識別的智能化解決方案。 二、系統架構設計 &#xff0…

SQL的底層邏輯解析

SQL的底層邏輯涉及數據庫管理系統(DBMS)如何解析、優化和執行SQL查詢&#xff0c;主要包括以下幾個層面&#xff1a; ?查詢處理流程? 解析器(Parser)&#xff1a;將SQL語句轉換為語法樹查詢優化器(Optimizer)&#xff1a;基于統計信息和成本模型生成最優執行計劃執行引擎(Exe…