Spring Boot 登錄實現:JWT 與 Session 全面對比與實戰講解

Spring Boot 登錄實現:JWT 與 Session 全面對比與實戰講解

2025.5.21-23:11今天在學習黑馬點評時突然發現用的是與蒼穹外賣jwt不一樣的登錄方式-Session,于是就想記錄一下這兩種方式有什么不同

在實際開發中,登錄認證是后端最基礎也是最重要的模塊之一。常見的實現方式主要有兩種:Session 登錄JWT(JSON Web Token)登錄

下面將從原理、使用場景、優缺點、代碼結構等角度,來對比這兩種方案,然后給出 Spring Boot 中的實際應用建議,幫助在實際項目中做出合理選擇。

一、登錄認證基本流程

無論是 JWT 還是 Session,登錄的本質流程都是:

  1. 用戶發送用戶名和密碼;
  2. 后端驗證成功后,生成認證信息;
  3. 后端將認證信息返回給客戶端;
  4. 客戶端攜帶認證信息訪問受保護接口;
  5. 后端驗證該認證信息是否合法。

二、Session 登錄機制

1. 原理說明

  • 用戶第一次登錄成功后,服務器創建一個 Session,并在服務器內存或 Redis 中保存用戶信息;
  • 同時將 Session ID 寫入到瀏覽器的 Cookie 中;
  • 用戶每次請求都會自動攜帶該 Cookie,服務器根據 Session ID 獲取用戶信息。
    在這里插入圖片描述

2. 代碼實現示例

登錄接口:
@PostMapping("/login")
public Result login(@RequestBody LoginDTO loginDTO, HttpSession session) {User user = userService.login(loginDTO);session.setAttribute("user", user);return Result.success();
}
攔截器判斷是否登錄:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {Object user = request.getSession().getAttribute("user");if (user == null) {response.setStatus(401);return false;}return true;
}

三、JWT 登錄機制

1. 原理說明

  • 用戶登錄成功后,服務器簽發一個加密的 JWT Token;
  • 客戶端將 Token 保存在 LocalStorage 或 Cookie;
  • 每次請求都將 Token 放在 Authorization 請求頭中;
  • 服務器解析并驗證 Token,從中讀取用戶信息。
    在這里插入圖片描述

2. JWT Token 的組成

JWT 一般由三部分組成:

Header.Payload.Signature

例如:

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEyMywidXNlcm5hbWUiOiJsaTIzIn0.sD_Kpdi2M...

3. JWT 登錄代碼示例

登錄生成 Token:
@PostMapping("/login")
public Result login(@RequestBody LoginDTO loginDTO) {User user = userService.login(loginDTO);String token = JwtUtil.generateToken(user); // 自定義工具類生成 tokenreturn Result.success(token);
}
前端請求攜帶 Token:
GET /user/info HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
攔截器驗證 Token:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader("Authorization");Claims claims = JwtUtil.parseToken(token);if (claims == null) {response.setStatus(401);return false;}return true;
}

在這里插入圖片描述

四、Session vs JWT 對比總結

特性SessionJWT
存儲位置服務端(內存/Redis)客戶端(LocalStorage/Cookie)
狀態性有狀態無狀態
跨域支持不友好(需處理 Cookie)友好
性能頻繁讀寫服務端存儲只需簽名驗證
安全性較高(信息在服務端)中等(需防止 Token 泄露)
適用場景傳統 Web 應用前后端分離、微服務、移動端

五、實戰項目推薦

在實際項目中,建議根據以下場景選擇:

  • 中小型 Web 應用:推薦使用 Session,實現簡單,安全性高;
  • 前后端分離項目:推薦使用 JWT,無狀態,跨域友好;
  • 大型系統:考慮 JWT + Session 混合使用,結合兩者優勢。

六、JWT 常見安全建議

  1. 設置過期時間(exp),避免 token 永久有效;
  2. 使用 HTTPS,防止 Token 被中間人截獲;
  3. 配合 Refresh Token 實現續簽;
  4. 用戶登出時將 Token 加入 Redis 黑名單;
  5. Token 不應包含敏感信息(如密碼、身份證號等)。

七、總結

Session 和 JWT 各有優缺點,選擇時需根據項目實際情況權衡:

  • Session 適合傳統 Web 應用,安全性高,實現簡單;
  • JWT 適合前后端分離、微服務架構,無狀態,擴展性強。

在實際開發中,還可以結合兩者的優勢,實現更靈活、安全的認證方案。

八、登錄超時控制

1. Session 登錄的過期控制

# application.yml 中配置 Session 失效時間(單位分鐘)
server:servlet:session:timeout: 30

Session 登錄通常依賴瀏覽器 Cookie,每次請求自動續期,適合長期在線場景。

2. JWT 的過期控制

JWT 自帶 exp 字段,在生成 Token 時設置過期時間:

// JwtUtil 生成 Token 示例
public static String generateToken(User user) {Date now = new Date();Date expireDate = new Date(now.getTime() + EXPIRE_TIME); // 設置過期時間return Jwts.builder().setHeaderParam("typ", "JWT").setSubject(user.getId().toString()).setIssuedAt(now).setExpiration(expireDate).claim("username", user.getUsername()).signWith(SignatureAlgorithm.HS512, SECRET) // 簽名加密.compact();
}

九、JWT 的刷新機制(Refresh Token)

為了避免用戶頻繁登錄,可以實現 Refresh Token 機制:

  1. 登錄時生成兩個 Token:AccessToken(短過期)和 RefreshToken(長過期);
  2. AccessToken 過期后,使用 RefreshToken 重新獲取 AccessToken;
  3. RefreshToken 也過期時,才需要用戶重新登錄。
// 登錄接口返回兩個 Token
@PostMapping("/login")
public Result login(@RequestBody LoginDTO loginDTO) {User user = userService.login(loginDTO);String accessToken = JwtUtil.generateAccessToken(user);String refreshToken = JwtUtil.generateRefreshToken(user);Map<String, String> tokens = new HashMap<>();tokens.put("accessToken", accessToken);tokens.put("refreshToken", refreshToken);return Result.success(tokens);
}// 刷新 Token 接口
@PostMapping("/refreshToken")
public Result refreshToken(@RequestBody RefreshTokenDTO dto) {// 驗證 RefreshToken 有效性Claims claims = JwtUtil.parseRefreshToken(dto.getRefreshToken());if (claims == null) {return Result.error("登錄已過期,請重新登錄");}// 重新生成 AccessTokenUser user = userService.getById(Long.valueOf(claims.getSubject()));String accessToken = JwtUtil.generateAccessToken(user);return Result.success(accessToken);
}

十、登出與 Redis 黑名單機制

JWT 本身無法主動失效,但可以通過 Redis 黑名單實現:

// 登出接口
@PostMapping("/logout")
public Result logout(HttpServletRequest request) {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7);// 解析 Token 獲取過期時間Claims claims = JwtUtil.parseToken(token);if (claims != null) {Date expireDate = claims.getExpiration();long expireSeconds = (expireDate.getTime() - System.currentTimeMillis()) / 1000;// 將 Token 加入 Redis 黑名單,直到過期redisTemplate.opsForValue().set("jwt:blacklist:" + token, "invalid", expireSeconds, TimeUnit.SECONDS);}}return Result.success();
}// 攔截器中檢查黑名單
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7);// 檢查黑名單if (redisTemplate.hasKey("jwt:blacklist:" + token)) {response.setStatus(401);return false;}// 驗證 TokenClaims claims = JwtUtil.parseToken(token);if (claims == null) {response.setStatus(401);return false;}// 將用戶信息存入請求request.setAttribute("userId", claims.getSubject());}return true;
}

十一、實際開發中推薦的 JWT 完整實現流程圖

用戶登錄請求
│
▼
后端驗證用戶名密碼
│
▼
驗證成功
│
├─┬─ 生成 AccessToken(含用戶 ID、角色等)
│ │
│ ├─ 生成 RefreshToken(與用戶 ID 綁定)
│ │
│ └─ 將 RefreshToken 存入 Redis(設置過期時間)
│
▼
返回 AccessToken 和 RefreshToken 給前端
│
▼
前端保存 Token(如 LocalStorage)
│
▼
前端每次請求攜帶 AccessToken(放在 Header)
│
▼
后端攔截器驗證 AccessToken
│
├─ 驗證失敗 ──┐
│             │
│             ▼
│      返回 401 未授權
│             │
│             ▼
│  前端使用 RefreshToken 請求新 AccessToken
│             │
│             ▼
│  后端驗證 RefreshToken
│             │
│     ┌───────┴───────┐
│     │               │
│  有效              無效
│     │               │
│     ▼               ▼
│  生成新 Token     用戶重新登錄
│     │
│     ▼
返回新 AccessToken

十二、附錄:JWT 工具類參考實現

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.HashMap;
import java.util.Map;@Component
public class JwtUtil {@Value("${jwt.secret}")private String secret;@Value("${jwt.accessTokenExpireTime}")private long accessTokenExpireTime; // 分鐘@Value("${jwt.refreshTokenExpireTime}")private long refreshTokenExpireTime; // 天/*** 生成 Access Token*/public String generateAccessToken(User user) {Map<String, Object> claims = new HashMap<>();claims.put("username", user.getUsername());claims.put("roles", user.getRoles());return generateToken(user.getId().toString(), claims, accessTokenExpireTime * 60 * 1000);}/*** 生成 Refresh Token*/public String generateRefreshToken(User user) {return generateToken(user.getId().toString(), null, refreshTokenExpireTime * 24 * 60 * 60 * 1000);}/*** 生成 Token*/private String generateToken(String subject, Map<String, Object> claims, long expireTime) {Date now = new Date();Date expireDate = new Date(now.getTime() + expireTime);return Jwts.builder().setHeaderParam("typ", "JWT").setClaims(claims).setSubject(subject).setIssuedAt(now).setExpiration(expireDate).signWith(SignatureAlgorithm.HS512, secret).compact();}/*** 解析 Token*/public Claims parseToken(String token) {try {return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {return null;}}/*** 驗證 Token 是否過期*/public boolean isTokenExpired(String token) {Claims claims = parseToken(token);if (claims == null) {return true;}Date expiration = claims.getExpiration();return expiration.before(new Date());}
}

十三、JWT 與 Session 混合使用的實踐方案

在一些大型系統中,可能存在不同端口或子系統使用不同的認證方式(如后臺管理系統用 Session,移動端用 JWT),這時可以采用 混合認證策略

1. 使用建議

模塊建議認證方式
管理后臺(單體、Spring MVC)使用 Session(Cookie 自動管理,方便權限控制)
移動端 / 小程序 / H5使用 JWT(無狀態認證,跨域安全,適合 API)
多端統一用戶體系JWT + Session 混合,并通過 Redis 存儲登錄狀態

2. 核心實現思路

  • 登錄成功時,服務端生成 JWT,同時創建一個短 Session,用于后臺系統交互;
  • Redis 中統一存儲用戶 Token 狀態,便于管理和失效控制;
  • 攔截器判斷請求來源(如是否含 Authorization),自動適配認證方式。

十四、常見問題 FAQ

Q1:JWT 一旦泄露是否會被無限使用?

是的,如果沒有設置過期時間或失效機制(如黑名單),Token 會一直有效。所以必須:

  • 設置過期時間;
  • 使用 HTTPS;
  • 實現登出邏輯(Redis 黑名單);

Q2:JWT 是不是比 Session 更安全?

不完全正確。JWT 只是在無狀態架構下更合適,但它暴露信息在客戶端,若加密不嚴密,反而更容易被篡改或偽造。而 Session 只存在服務端,反而更隱蔽和安全。

Q3:JWT 必須存放在 LocalStorage 嗎?

不一定。也可以存放在:

  • LocalStorage(常見方式,刷新頁面不丟失);
  • SessionStorage(更安全,但刷新頁面會清空);
  • HttpOnly Cookie(防 XSS,但不支持 JS 訪問,需配合后端設置跨域 Cookie);

十六、推薦學習與實踐路徑

1. 學會使用 Spring MVC + Session 登錄機制

在 Spring MVC 項目中,Session 登錄是一種傳統且有效的認證方式。
登錄接口實現
通過 HttpSession 對象將用戶信息存入 Session:

@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password, HttpSession session) {User user = userService.login(username, password);if (user != null) {session.setAttribute("user", user); // 存入 Sessionreturn "redirect:/home"; // 登錄成功跳轉}return "login"; // 登錄失敗返回登錄頁
}

攔截器驗證登錄狀態
編寫攔截器檢查 Session 中是否存在用戶信息:

@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HttpSession session = request.getSession();User user = (User) session.getAttribute("user");if (user == null) { // 未登錄則重定向到登錄頁response.sendRedirect("/login");return false;}return true; // 已登錄,允許訪問}
}

注冊攔截器
在 Spring MVC 配置類中指定攔截路徑(如 /api/**)和排除路徑(如 /login):

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/api/**") // 攔截所有 API 接口.excludePathPatterns("/login", "/static/**"); // 排除登錄頁和靜態資源}
}

2. 掌握前后端分離項目中 JWT 的基本使用方式

JWT 工具類實現
生成和解析 Token,包含過期時間和簽名加密:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;public class JwtUtil {private static final String SECRET = "your_secret_key_keep_it_secure"; // 密鑰(需保密)private static final long EXPIRATION_TIME = 3600000; // 1小時(毫秒)// 生成 Tokenpublic static String generateToken(String username) {Claims claims = Jwts.claims().setSubject(username); // 載荷存儲用戶標識Date now = new Date();Date expiration = new Date(now.getTime() + EXPIRATION_TIME); // 設置過期時間return Jwts.builder().setClaims(claims).setIssuedAt(now).setExpiration(expiration).signWith(SignatureAlgorithm.HS256, SECRET) // HS256 簽名算法.compact();}// 解析 Tokenpublic static Claims parseToken(String token) {try {return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody(); // 成功解析返回載荷} catch (Exception e) {return null; // 解析失敗返回 null}}
}

登錄接口返回 Token
驗證用戶信息后生成 Token 并返回給前端:

@PostMapping("/login")
public ResponseEntity<Map<String, String>> login(@RequestBody UserLoginRequest request) {User user = userService.authenticate(request.getUsername(), request.getPassword());if (user != null) {String token = JwtUtil.generateToken(user.getUsername());Map<String, String> result = new HashMap<>();result.put("token", token);return ResponseEntity.ok(result); // 返回 Token}return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); // 認證失敗
}

后端驗證 Token
通過攔截器從請求頭中獲取 Token 并解析驗證:

public class JwtInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7); // 去除 "Bearer " 前綴Claims claims = JwtUtil.parseToken(token);if (claims != null) {// 解析成功,將用戶信息存入請求(如用戶 ID、角色)request.setAttribute("userId", claims.getSubject());return true;}}response.setStatus(HttpStatus.UNAUTHORIZED); // 未認證或 Token 無效return false;}
}

3. 實現 Token 過期 + 刷新機制

雙 Token 設計

  • AccessToken:短有效期(如 1 小時),用于接口認證;
  • RefreshToken:長有效期(如 7 天),用于刷新 AccessToken。

登錄時返回雙 Token

@PostMapping("/login")
public ResponseEntity<Map<String, String>> login(@RequestBody UserLoginRequest request) {User user = userService.authenticate(request.getUsername(), request.getPassword());if (user != null) {String accessToken = JwtUtil.generateToken(user.getUsername(), "access"); // 短過期String refreshToken = JwtUtil.generateToken(user.getUsername(), "refresh"); // 長過期Map<String, String> tokens = new HashMap<>();tokens.put("accessToken", accessToken);tokens.put("refreshToken", refreshToken);return ResponseEntity.ok(tokens);}return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
}

刷新 Token 接口
使用 RefreshToken 生成新的 AccessToken:

@PostMapping("/refresh-token")
public ResponseEntity<Map<String, String>> refreshToken(@RequestHeader("Refresh-Token") String refreshToken) {Claims claims = JwtUtil.parseToken(refreshToken);if (claims != null && "refresh".equals(claims.get("type"))) { // 驗證 Token 類型String username = claims.getSubject();String newAccessToken = JwtUtil.generateToken(username, "access"); // 生成新 AccessTokenMap<String, String> result = new HashMap<>();result.put("accessToken", newAccessToken);return ResponseEntity.ok(result);}return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
}

在這里插入圖片描述

4. 實現 Redis 黑名單、登錄限制、踢出機制

Redis 黑名單
用戶登出時將 Token 加入 Redis 黑名單,設置與 Token 剩余有效期一致的過期時間:

@Autowired
private RedisTemplate<String, Object> redisTemplate;// 登出邏輯
public void logout(String token) {Claims claims = JwtUtil.parseToken(token);if (claims != null) {long expireTime = claims.getExpiration().getTime() - System.currentTimeMillis();if (expireTime > 0) {redisTemplate.opsForValue().set("blacklist:" + token, "invalid", expireTime, TimeUnit.MILLISECONDS);}}
}// 攔截器中檢查黑名單
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader("Authorization");if (redisTemplate.hasKey("blacklist:" + token)) { // 存在于黑名單則拒絕訪問response.setStatus(HttpStatus.UNAUTHORIZED);return false;}// 其他驗證邏輯...return true;
}

登錄頻率限制
使用 Redis 記錄用戶登錄次數,限制每分鐘最多 5 次嘗試:

public boolean checkLoginFrequency(String username) {String key = "login:attempts:" + username;Integer count = (Integer) redisTemplate.opsForValue().get(key);if (count != null && count >= 5) { // 超過限制return false; // 禁止登錄}// 次數加 1,設置過期時間 1 分鐘redisTemplate.opsForValue().increment(key, 1);redisTemplate.expire(key, 1, TimeUnit.MINUTES);return true;
}

管理員踢出用戶
將用戶所有有效 Token 加入黑名單(需結合用戶 ID 批量操作):

public void kickUser(String userId) {// 查詢用戶所有有效 Token(需業務系統存儲 Token 與用戶的映射)List<String> tokens = tokenRepository.findByUserId(userId);tokens.forEach(token -> logout(token)); // 批量加入黑名單
}

5. 掌握 Spring Security 對 JWT 的整合

自定義 JWT 認證過濾器
繼承 OncePerRequestFilter,解析 Token 并設置安全上下文:

public class JwtAuthenticationFilter extends OncePerRequestFilter {private final JwtUtil jwtUtil;public JwtAuthenticationFilter(JwtUtil jwtUtil) {this.jwtUtil = jwtUtil;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7);Claims claims = jwtUtil.parseToken(token);if (claims != null) {String username = claims.getSubject();// 構建認證對象(可添加角色權限)Authentication authentication = new UsernamePasswordAuthenticationToken(username, null, Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));SecurityContextHolder.getContext().setAuthentication(authentication); // 設置安全上下文}}filterChain.doFilter(request, response); // 繼續執行后續過濾器}
}

Spring Security 配置
禁用 CSRF,添加 JWT 過濾器并配置權限規則:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final JwtUtil jwtUtil;public SecurityConfig(JwtUtil jwtUtil) {this.jwtUtil = jwtUtil;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable() // 前后端分離場景禁用 CSRF.authorizeRequests().antMatchers(HttpMethod.POST, "/login").permitAll() // 允許登錄接口.antMatchers("/admin/**").hasRole("ADMIN") // 管理員接口需 ADMIN 角色.anyRequest().authenticated() // 其他接口需認證.and().addFilterBefore(new JwtAuthenticationFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); // 添加 JWT 過濾器}
}

通過 Spring Security 的整合,可更便捷地實現細粒度權限控制(如 @PreAuthorize 注解)和安全策略管理。

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

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

相關文章

Vue中的 VueComponent

VueComponent 組件的本質 Vue 組件是一個可復用的 Vue 實例。每個組件本質上就是通過 Vue.extend() 創建的構造函數&#xff0c;或者在 Vue 3 中是由函數式 API&#xff08;Composition API&#xff09;創建的。 // Vue 2 const MyComponent Vue.extend({template: <div…

使用 FFmpeg 將視頻轉換為高質量 GIF(保留原始尺寸和幀率)

在制作教程動圖、產品展示、前端 UI 演示等場景中,我們經常需要將視頻轉換為體積合適且清晰的 GIF 動圖。本文將詳細介紹如何使用 FFmpeg 工具將視頻轉為高質量 GIF,包括: ? 保留原視頻尺寸或自定義縮放? 保留原始幀率或自定義幀率? 使用調色板優化色彩質量? 降低體積同…

【自然語言處理與大模型】大模型Agent四大的組件

大模型Agent是基于大型語言模型構建的智能體&#xff0c;它們能夠模擬獨立思考過程&#xff0c;靈活調用各類工具&#xff0c;逐步達成預設目標。這類智能體的設計旨在通過感知、思考與行動三者的緊密結合來完成復雜任務。下面將從大模型大腦&#xff08;LLM&#xff09;、規劃…

《軟件工程》第 11 章 - 結構化軟件開發

結構化軟件開發是一種傳統且經典的軟件開發方法&#xff0c;它強調將軟件系統分解為多個獨立的模塊&#xff0c;通過數據流和控制流來描述系統的行為。本章將結合 Java 代碼示例、可視化圖表&#xff0c;深入講解面向數據流的分析與設計方法以及實時系統設計的相關內容。 11.1 …

初步嘗試AI應用開發平臺——Dify的本地部署和應用開發

隨著大語言模型LLM和相關應用的流行&#xff0c;在本地部署并構建知識庫&#xff0c;結合企業的行業經驗或個人的知識積累進行定制化開發&#xff0c;是LLM的一個重點發展方向&#xff0c;在此方向上也涌現出了眾多軟件框架和工具集&#xff0c;Dify就是其中廣受關注的一款&…

高階數據結構——哈希表的實現

目錄 1.概念引入 2.哈希的概念&#xff1a; 2.1 什么叫映射&#xff1f; 2.2 直接定址法 2.3 哈希沖突&#xff08;哈希碰撞&#xff09; 2.4 負載因子 2.5 哈希函數 2.5.1 除法散列法&#xff08;除留余數法&#xff09; 2.5.2 乘法散列法&#xff08;了解&#xff09…

7.安卓逆向2-frida hook技術-介紹

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 內容參考于&#xff1a;圖靈Python學院 工具下載&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取碼&#xff1…

DB-GPT擴展自定義Agent配置說明

簡介 文章主要介紹了如何擴展一個自定義Agent&#xff0c;這里是用官方提供的總結摘要的Agent做了個示例&#xff0c;先給大家看下顯示效果 代碼目錄 博主將代碼放在core目錄了&#xff0c;后續經過對源碼的解讀感覺放在dbgpt_serve.agent.agents.expand目錄下可能更合適&…

Android 架構演進之路:從 MVC 到 MVI,擁抱單向數據流的革命

在移動應用開發的世界里&#xff0c;架構模式的演進從未停歇。從早期的 MVC 到后來的 MVP、MVVM&#xff0c;每一次變革都在嘗試解決前一代架構的痛點。而今天&#xff0c;我們將探討一種全新的架構模式 ——MVI&#xff08;Model-View-Intent&#xff09;&#xff0c;它借鑒了…

【YOLOv8-pose部署至RK3588】模型訓練→轉換RKNN→開發板部署

已在GitHub開源與本博客同步的YOLOv8_RK3588_object_pose 項目&#xff0c;地址&#xff1a;https://github.com/A7bert777/YOLOv8_RK3588_object_pose 詳細使用教程&#xff0c;可參考README.md或參考本博客第六章 模型部署 文章目錄 一、項目回顧二、文件梳理三、YOLOv8-pose…

集成30+辦公功能的實用工具

軟件介紹 本文介紹的軟件是千峰辦公助手。 軟件功能概述與開發目的 千峰辦公助手集成了自動任務、系統工具、文件工具、PDF工具、OCR圖文識別、文字處理、電子表格七個模塊&#xff0c;擁有30余項實用功能。作者開發該軟件的目的是解決常見辦公痛點&#xff0c;把機械操作交…

IDEA啟動報錯:Cannot invoke “org.flowable.common.engine.impl.persistence.ent

1.問題 項目啟動報錯信息 java.lang.NullPointerException: Cannot invoke "org.flowable.common.engine.impl.persistence.ent 2.問題解析 出現這個問題是在項目中集成了Flowable或Activiti工作流&#xff0c;開啟自動創建工作流創建的表&#xff0c;因為不同環境的數據…

網絡安全--PHP第三天

今天學習文件上傳的相關知識 上傳的前端頁面如下 upload.html <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&g…

【愚公系列】《生產線數字化設計與仿真》004-顏色分類站仿真(基礎概念)

??【技術大咖愚公搬代碼:全棧專家的成長之路,你關注的寶藏博主在這里!】?? ??開發者圈持續輸出高質量干貨的"愚公精神"踐行者——全網百萬開發者都在追更的頂級技術博主! ?? 江湖人稱"愚公搬代碼",用七年如一日的精神深耕技術領域,以"…

基于 uni-app + <movable-view>拖拽實現的標簽排序-適用于微信小程序、H5等多端

在實際業務中&#xff0c;我們經常遇到「標簽排序」或「菜單調整」的場景。微信小程序原生的 movable-view 為我們提供了一個簡單、高效的拖拽能力&#xff0c;結合 Vue3 uni-app 的組合&#xff0c;我們可以實現一個體驗良好的標簽管理界面。 核心組件&#xff1a;<movab…

一些較好的學習方法

1、網上有一些非常經典的電路&#xff0c;而且有很多視頻博主做了詳細的講解。 2、有一部分拆解的UP主&#xff0c;拆解后會還原該器件的原理圖&#xff0c;并一步步做講解。 3、有兩本書&#xff0c;數電、模電&#xff0c;這兩本書中的內容很多都值得學習。 5、某寶上賣的…

《1.1_4計算機網絡的分類|精講篇|附X-mind思維導圖》

網絡相關知識 按使用范圍分類 公用網 由電信部門或其他提供通信服務的經營部門組建、管理和控制&#xff0c;向全社會提供服務的網絡。 專用網 由某個單位或部門組建、僅供本單位或部門內部使用的網絡。 按傳輸介質分類 有線網絡 如&#xff1a;雙絞線、同軸電纜、光纖…

Git 和 GitHub 學習指南本地 Git 配置、基礎命令、GitHub 上傳流程、企業開發中 Git 的使用流程、以及如何將代碼部署到生產服務器

Windows 上 Git 安裝與配置 下載安裝&#xff1a;訪問 Git 官方網站下載適用于 Windows 的安裝程序。運行安裝包時會出現許可協議、安裝目錄、組件選擇等界面&#xff08;如下圖&#xff09;。在“Select Components”頁面建議勾選 Git Bash Here 等選項&#xff0c;以便在資源…

航空航天領域對滾珠絲桿的精度要求有多高?

航空航天領域對滾珠絲桿的精度要求非常高&#xff0c;尤其是飛行器、火箭和衛星等載具的導航和定位系統都需要高精度的滾珠絲桿&#xff0c;以確保高精度的位置控制和穩定的導航性能。那么&#xff0c;航空航天領域對滾珠絲桿的精度要求有多高&#xff1f; 1、定位精度&#xf…

技術篇-2.5.Matlab應用場景及開發工具安裝

Matlab 在數學建模和數值分析等領域具有無可替代的地位。它幾乎涵蓋所有常見數學算法的內置函數庫&#xff0c;使得從數據預處理、方程求解到優化算法的實現&#xff0c;無需編寫大量底層代碼即可快速完成&#xff1b;同時&#xff0c;Matlab 強大的可視化能力&#xff0c;可以…