jwt 實現用戶登錄完整java

登錄校驗邏輯

用戶登錄的校驗邏輯分為三個主要步驟,分別是校驗驗證碼校驗用戶狀態校驗密碼,具體邏輯如下

  • 前端發送usernamepasswordcaptchaKeycaptchaCode請求登錄。
  • 判斷captchaCode是否為空,若為空,則直接響應驗證碼為空;若不為空進行下一步判斷。
  • 根據captchaKey從Redis中查詢之前保存的code,若查詢出來的code為空,則直接響應驗證碼已過期;若不為空進行下一步判斷。
  • 比較captchaCodecode,若不相同,則直接響應驗證碼不正確;若相同則進行下一步判斷。
  • 根據username查詢數據庫,若查詢結果為空,則直接響應賬號不存在;若不為空則進行下一步判斷。
  • 查看用戶狀態,判斷是否被禁用,若禁用,則直接響應賬號被禁;若未被禁用,則進行下一步判斷。
  • 比對password和數據庫中查詢的密碼,若不一致,則直接響應賬號或密碼錯誤,若一致則進行入最后一步。
  • 創建JWT,并響應給瀏覽器。

請求數據結構

package com.orchids.springmybatisplus.model.entity;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;/*** @Author qwh* @Date 2024/6/2 22:31*/
@Data
@Schema(description = "后臺管理系統登錄信息")
public class LoginVo {@Schema(description="用戶名")private String username;@Schema(description="密碼")private String password;@Schema(description="驗證碼key")private String captchaKey;@Schema(description="驗證碼code")private String captchaCode;
}

枚舉類

package com.orchids.lovehouse.common.result;import lombok.Getter;/*** 統一返回結果狀態信息類*/
@Getter
public enum ResultCodeEnum {SUCCESS(200, "成功"),FAIL(201, "失敗"),PARAM_ERROR(202, "參數不正確"),SERVICE_ERROR(203, "服務異常"),DATA_ERROR(204, "數據異常"),ILLEGAL_REQUEST(205, "非法請求"),REPEAT_SUBMIT(206, "重復提交"),DELETE_ERROR(207, "請先刪除子集"),ADMIN_ACCOUNT_EXIST_ERROR(301, "賬號已存在"),ADMIN_CAPTCHA_CODE_ERROR(302, "驗證碼錯誤"),ADMIN_CAPTCHA_CODE_EXPIRED(303, "驗證碼已過期"),ADMIN_CAPTCHA_CODE_NOT_FOUND(304, "未輸入驗證碼"),ADMIN_ACCOUNT_NOT_EXIST(330,"用戶不存在"),ADMIN_LOGIN_AUTH(305, "未登陸"),ADMIN_ACCOUNT_NOT_EXIST_ERROR(306, "賬號不存在"),ADMIN_ACCOUNT_ERROR(307, "用戶名或密碼錯誤"),ADMIN_ACCOUNT_DISABLED_ERROR(308, "該用戶已被禁用"),ADMIN_ACCESS_FORBIDDEN(309, "無訪問權限"),APP_LOGIN_AUTH(501, "未登陸"),APP_LOGIN_PHONE_EMPTY(502, "手機號碼為空"),APP_LOGIN_CODE_EMPTY(503, "驗證碼為空"),APP_SEND_SMS_TOO_OFTEN(504, "驗證法發送過于頻繁"),APP_LOGIN_CODE_EXPIRED(505, "驗證碼已過期"),APP_LOGIN_CODE_ERROR(506, "驗證碼錯誤"),APP_ACCOUNT_DISABLED_ERROR(507, "該用戶已被禁用"),TOKEN_EXPIRED(601, "token過期"),TOKEN_INVALID(602, "token非法");private final Integer code;private final String message;ResultCodeEnum(Integer code, String message) {this.code = code;this.message = message;}
}

全局異常處理

package com.orchids.lovehouse.common.exception;import com.orchids.lovehouse.common.result.ResultCodeEnum;
import lombok.Data;/*** @Author qwh* @Date 2024/6/1 20:18*/
@Data
public class LovehouseException extends RuntimeException {//異常狀態碼private Integer code;/*** 通過狀態碼和錯誤消息創建異常對象* @param message* @param code*/public LovehouseException(String message, Integer code) {super(message);this.code = code;}/*** 根據響應結果枚舉對象創建異常對象* @param resultCodeEnum*/public LovehouseException(ResultCodeEnum resultCodeEnum) {super(resultCodeEnum.getMessage());this.code = resultCodeEnum.getCode();}@Overridepublic String toString() {return "LovehouseException{" +"code=" + code +", message=" + this.getMessage() +'}';}
}

配置所需依賴
登錄接口需要為登錄成功的用戶創建并返回JWT,本項目使用開源的JWT工具Java-JWT,配置如下,具體內容可參考官方文檔。

  • 引入Maven依賴
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.2</version>
</dependency><dependency><!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.2</version><scope>runtime</scope>
</dependency><!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.2</version><scope>runtime</scope>
</dependency>

創建JWT和工具類 common.utils.JwtUtil

package com.orchids.lovehouse.common.utils;import com.orchids.lovehouse.common.exception.LovehouseException;
import com.orchids.lovehouse.common.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;import javax.crypto.SecretKey;
import java.util.Date;/*** @Author qwh* @Date 2024/6/2 21:01*/
public class JwtUtil {private static long tokenExpiration = 60  * 60 * 1000L;public static SecretKey secretKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes());public static String createToken(Long userId,String username){String token  = Jwts.builder().setSubject("USER_INFO").setExpiration(new Date(System.currentTimeMillis()+tokenExpiration)).claim("userId",userId).claim("username",username).signWith(secretKey,SignatureAlgorithm.HS256).compact();return token;}public static Claims parsToken(String token){if (token==null) {throw new LovehouseException(ResultCodeEnum.ADMIN_LOGIN_AUTH);}try {JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();Jws<Claims> claims = jwtParser.parseClaimsJws(token);return claims.getBody();} catch (ExpiredJwtException e) {throw new LovehouseException(ResultCodeEnum.TOKEN_EXPIRED);} catch (JwtException e){throw new LovehouseException(ResultCodeEnum.TOKEN_INVALID);}}public static void main(String[] args) {System.out.println(createToken(2l,"user"));}
}

controller邏輯

package com.orchids.lovehouse.web.admin.controller.login;import com.orchids.lovehouse.common.login.LoginUserHolder;
import com.orchids.lovehouse.common.result.Result;
import com.orchids.lovehouse.common.utils.JwtUtil;
import com.orchids.lovehouse.web.admin.service.LoginService;
import com.orchids.lovehouse.web.admin.vo.login.CaptchaVo;
import com.orchids.lovehouse.web.admin.vo.login.LoginVo;
import com.orchids.lovehouse.web.admin.vo.system.user.SystemUserInfoVo;
import com.orchids.lovehouse.web.admin.vo.system.user.SystemUserItemVo;
import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@Tag(name = "后臺管理系統登錄管理")
@RestController
@RequestMapping("/admin")
public class LoginController {@Autowiredprivate LoginService loginService;@Operation(summary = "獲取圖形驗證碼")@GetMapping("login/captcha")public Result<CaptchaVo> getCaptcha() {CaptchaVo captcha = loginService.getCaptcha();return Result.ok(captcha);}@Operation(summary = "登錄")@PostMapping("login")public Result<String> login(@RequestBody LoginVo loginVo) {String token =  loginService.login(loginVo);return Result.ok(token);}@Operation(summary = "獲取登陸用戶個人信息")@GetMapping("info")public Result<SystemUserInfoVo> info () {SystemUserInfoVo systemUserInfo  = loginService.getLoginUserInfo(LoginUserHolder.getLoginUser().getUserId());return Result.ok(systemUserInfo);}
}

service邏輯

package com.orchids.lovehouse.web.admin.service;import com.orchids.lovehouse.web.admin.vo.login.CaptchaVo;
import com.orchids.lovehouse.web.admin.vo.login.LoginVo;
import com.orchids.lovehouse.web.admin.vo.system.user.SystemUserInfoVo;public interface LoginService {CaptchaVo getCaptcha();String login(LoginVo loginVo);SystemUserInfoVo getLoginUserInfo(Long userId);
}

sreviceImpl

package com.orchids.lovehouse.web.admin.service.impl;import com.orchids.lovehouse.common.constant.RedisConstant;
import com.orchids.lovehouse.common.exception.GlobalExceptionHandler;
import com.orchids.lovehouse.common.exception.LovehouseException;
import com.orchids.lovehouse.common.result.ResultCodeEnum;
import com.orchids.lovehouse.common.utils.JwtUtil;
import com.orchids.lovehouse.model.entity.SystemUser;
import com.orchids.lovehouse.model.enums.BaseStatus;
import com.orchids.lovehouse.web.admin.mapper.SystemUserMapper;
import com.orchids.lovehouse.web.admin.service.LoginService;
import com.orchids.lovehouse.web.admin.vo.login.CaptchaVo;
import com.orchids.lovehouse.web.admin.vo.login.LoginVo;
import com.orchids.lovehouse.web.admin.vo.system.user.SystemUserInfoVo;
import com.orchids.lovehouse.web.admin.vo.system.user.SystemUserItemVo;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;import java.util.UUID;
import java.util.concurrent.TimeUnit;@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate SystemUserMapper systemUserMapper;@Overridepublic CaptchaVo getCaptcha() {SpecCaptcha  specCaptcha = new SpecCaptcha(100, 40, 5);specCaptcha.setCharType(Captcha.TYPE_DEFAULT);String code = specCaptcha.text().toLowerCase();String key = RedisConstant.ADMIN_LOGIN_PREFIX + UUID.randomUUID();String img = specCaptcha.toBase64();stringRedisTemplate.opsForValue().set(key,code,60, TimeUnit.SECONDS);return new CaptchaVo(img,key);}@Overridepublic String login(LoginVo loginVo) {//判斷是否輸入驗證碼if (!StringUtils.hasText(loginVo.getCaptchaCode())) {throw new LovehouseException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_NOT_FOUND);}//校驗驗證碼String code = stringRedisTemplate.opsForValue().get(loginVo.getCaptchaKey());if (code == null){throw new LovehouseException(ResultCodeEnum.APP_LOGIN_CODE_EXPIRED);}if (!code.equals(loginVo.getCaptchaCode())){throw new LovehouseException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);}//校驗用戶是否存在SystemUser systemUser = systemUserMapper.selectOneByUsername(loginVo.getUsername());if (systemUser == null) {throw new LovehouseException(ResultCodeEnum.ADMIN_ACCOUNT_NOT_EXIST);}if (systemUser.getStatus() == BaseStatus.DISABLE) {throw new LovehouseException(ResultCodeEnum.ADMIN_ACCOUNT_DISABLED_ERROR);}// 鏍¢獙鐢ㄦ埛瀵嗙爜if (!systemUser.getPassword().equals(DigestUtils.md5DigestAsHex(loginVo.getPassword().getBytes()))) {throw new LovehouseException(ResultCodeEnum.ADMIN_ACCOUNT_ERROR);}// 鍒涘緩騫惰繑鍥瀟okenreturn JwtUtil.createToken(systemUser.getId(),systemUser.getUsername());}@Overridepublic SystemUserInfoVo getLoginUserInfo(Long userId) {SystemUser systemUser = systemUserMapper.selectById(userId);SystemUserInfoVo systemUserInfoVo = new SystemUserInfoVo();systemUserInfoVo.setName(systemUser.getName());systemUserInfoVo.setAvatarUrl(systemUser.getAvatarUrl());return systemUserInfoVo;}}

編寫mapper邏輯

SystemUser selectOneByUsername(String username);

mapper.xml

寫入對應的sql到xml文件

編寫HandlerInterceptor
保護所有受保護的接口增加jwt合法性邏輯 custom.interceptor.AuthenticationInterceptor

package com.orchids.lovehouse.web.admin.custom.interceptor;import com.orchids.lovehouse.common.login.LoginUser;
import com.orchids.lovehouse.common.login.LoginUserHolder;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.orchids.lovehouse.common.utils.JwtUtil;/*** @Author qwh* @Date 2024/6/2 21:55*/
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("access-token");Claims claims = JwtUtil.parsToken(token);Long userId = claims.get("userId", Long.class);String username = claims.get("username", String.class);LoginUserHolder.setLoginUser(new LoginUser(userId,username));return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {LoginUserHolder.clear();}
}

我們約定,前端登錄后,后續請求都將JWT,放置于HTTP請求的Header中,其Header的key為access-token
注冊HanderInterceptor config.WebMvcConfiguration

package com.orchids.lovehouse.web.admin.custom.config;import com.orchids.lovehouse.web.admin.custom.converter.StringToBaseEnumConverterFactory;
import com.orchids.lovehouse.web.admin.custom.converter.StringToItemTypeConverter;
import com.orchids.lovehouse.web.admin.custom.interceptor.AuthenticationInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Autowiredprivate AuthenticationInterceptor authenticationInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(this.authenticationInterceptor).addPathPatterns("/admin/**").excludePathPatterns("/admin/login/**");}
}

獲取登錄個人信息
查看請求和響應的數據結構

  • 響應的數據結構
@Schema(description = "員工基本信息")
@Data
public class SystemUserInfoVo {@Schema(description = "用戶姓名")private String name;@Schema(description = "用戶頭像")private String avatarUrl;
}

common.login.LoginUserHolder

package com.orchids.lovehouse.common.login;/*** @Author qwh* @Date 2024/6/2 22:15*/
public class LoginUserHolder {public static ThreadLocal<LoginUser> threadLocal = new ThreadLocal<>();public static void setLoginUser(LoginUser loginUser) {threadLocal.set(loginUser);}public static LoginUser getLoginUser() {return threadLocal.get();}public static void clear() {threadLocal.remove();}
}

common.login.LoginUser

package com.orchids.lovehouse.common.login;import lombok.AllArgsConstructor;
import lombok.Data;/*** @Author qwh* @Date 2024/6/2 22:16*/
@Data
@AllArgsConstructor
public class LoginUser {private Long userId;private String username;
}

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

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

相關文章

AWS聯網和內容分發服務

概況 VPC Amazon Virtual Private Cloud (Amazon VPC) 讓您能夠全面地控制自己的虛擬網絡環境&#xff0c;包括資源放置、連接性和安全性。首先在 AWS 服務控制臺中設置 VPC。然后&#xff0c;向其中添加資源&#xff0c;例如 Amazon Elastic Compute Cloud (EC2) 和 Amazon …

數據分析必備:一步步教你如何用Pandas做數據分析(15)

1、Pandas 數據丟失 Pandas 數據丟失的操作實例 在現實生活中&#xff0c;數據丟失始終是一個問題。機器學習和數據挖掘等領域在模型預測的準確性方面面臨嚴重問題&#xff0c;因為缺少值會導致數據質量較差。在這些領域中&#xff0c;缺失值處理是使模型更準確和有效的主要重…

定個小目標之每天刷LeetCode熱題(7)

今天這道題是道簡單題&#xff0c;使用雙指針進行迭代即可&#xff0c;畫了下草圖如下 代碼如下 class Solution {public ListNode reverseList(ListNode head) {if (head null || head.next null) {return head;}ListNode p head, q head.next, temp null;while (q ! nu…

【Python如何將EXCEL拆分】

文章目錄 Python將一個EXCEL表拆分多個excel表Python將一個EXCEL表中一個sheet拆分多個sheet表 Python將一個EXCEL表拆分多個excel表 在Python中&#xff0c;你可以使用pandas庫來讀取Excel文件&#xff0c;并將一個大的Excel表格&#xff08;工作表&#xff09;拆分成多個單獨…

Writerside生成在線幫助文檔或用戶手冊軟件基礎使用教程

Writerside是JetBrains出的一個技術文檔工具&#xff0c;既能用在JetBrains IDE上&#xff0c;也能單獨用。它能幫你輕松寫、建、測、發技術文檔&#xff0c;像產品說明、API參考、開發指南等都能搞定。 特點&#xff1a; 文檔即代碼&#xff1a;它讓你像管代碼一樣管文檔&…

【大數據Spark】常見面試題(萬字!建議收藏)

文章目錄 入門級中等難度中高級難度數據傾斜解決方法 入門級 什么是Apache Spark&#xff1f;它與傳統的MapReduce有何不同&#xff1f; Apache Spark是一個開源的分布式計算系統&#xff0c;它提供了高效的數據處理和分析能力。與傳統的MapReduce相比&#xff0c;Spark具有更快…

海光CPU:國產信創的“芯“動力解讀

國產信創CPU-海光CPU CPU&#xff1a;信創根基&#xff0c;國之重器 國產CPU形成三大陣營&#xff1a;自主架構、x86及ARM。自主陣營中&#xff0c;龍芯和申威以LoongArch和SW-64為基石&#xff1b;ARM陣營由鯤鵬、飛騰主導&#xff0c;依托ARM授權研發處理器&#xff1b;x86陣…

紅帽練習 之邏輯卷 pv lv gv

邏輯卷習題 1 在/dev/sdb 存儲設備上創建物理設備分區 創建2個大小各為256MB的分區 并設置為linux lvm類型 使用first 和second 作為這些分區的名稱 parted /dev/sdb mklabel gpt parted /dev/sdb primary mkpart first 1M 256M parted /dev/sdb set 1 …

【Linux|數據恢復】extundelete和ext4magic數據恢復工具使用

環境&#xff1a;Centos7.6_x86 一、extundelete工具 1、extundelete介紹 Extundelete 是一個數據恢復工具&#xff0c;用于從 ext3 或 ext4 分區中恢復刪除文件。根據官網0.2.4版本介紹是支持ext4&#xff0c;但實際上使用發現ext4格式有些問題&#xff0c;會報以下錯誤&…

動態SQL IF語句

IF語句學習 第一種寫法(標準) 我們先來看以下標準寫法: select * from .. <where> <if test""> and ....... <if test""> and ....... <where> 我們用了一個where標簽 , 內嵌if語句 第二種寫法: 這是第二種寫法:不用where標…

大降分!重郵計算機專碩復試線大降50分!重慶郵電計算機考研考情分析!

重慶郵電大學&#xff08;Chongqing University of Posts and Telecommunications&#xff09;簡稱重郵&#xff0c;坐落于中國重慶市主城區南山風景區內&#xff0c;是中華人民共和國工業和信息化部與重慶市人民政府共建的教學研究型大學&#xff0c;入選國家“中西部高校基礎…

一篇文章搞懂Go語言切片底層原理(圖文并茂+舉例講解)

1. 切片和數組的底層關系 Go語言切片的數據結構是一個結構體&#xff1a; type slice struct {array unsafe.Pointerlen intcap int }Go語言中切片的內部結構包含地址、大小和容量。將數組比喻成一個蛋糕&#xff0c;那么切片就是需要切的那一塊&#xff0c;而那一塊的的…

c++學生管理系統

想要實現的功能 1&#xff0c;可以增加學生的信息&#xff0c;包括&#xff08;姓名&#xff0c;學號,c成績&#xff0c;高數成績&#xff0c;英語成績&#xff09; 2&#xff0c;可以刪除學生信息 3&#xff0c;修改學生信息 4&#xff0c;顯示所有學生信息 5&#xff0c…

支持AMD GPU的llm.c

anthonix/llm.c: LLM training in simple, raw C/HIP for AMD GPUs (github.com) llm.c for AMD devices This is a fork of Andrej Karpathys llm.c with support for AMD devices. 性能 在單個7900 XTX顯卡上使用默認設置&#xff0c;目前的訓練步驟耗時約為79毫秒&#x…

Docker的安裝、啟動和配置鏡像加速

前言&#xff1a; Docker 分為 CE 和 EE 兩大版本。CE 即社區版&#xff08;免費&#xff0c;支持周期 7 個月&#xff09;&#xff0c;EE 即企業版&#xff0c;強調安全&#xff0c;付費使用&#xff0c;支持周期 24 個月。 而企業部署一般都是采用Linux操作系統&#xff0c;而…

【軟件設計師】2022年上半年真題解析

??馮諾依曼計算機體系結構的基本特點是&#xff1a; A. 程序指令和數據都采用二進制表示 - 這是正確的&#xff0c;因為馮諾依曼架構下的計算機使用二進制形式來表示和處理所有信息&#xff0c;包括指令和數據。 B. 程序指令總是存儲在主存中&#xff0c;而數據則存儲在高速…

Java基礎語法詳解——入門學習教程

Java 基礎 目錄 一、數據類型 基本類型包裝類型緩存池 二、String 概覽不可變的好處String, StringBuffer and StringBuilder String Poolnew String(“abc”) 三、運算 參數傳遞float 與 double隱式類型轉換switch 四、關鍵字 finalstatic 五、Object 通用方法 概覽equals()ha…

深入解析 MongoDB Map-Reduce:強大數據聚合與分析的利器

Map-Reduce 是一種用于處理和生成大數據集的方法&#xff0c;MongoDB 支持 Map-Reduce 操作以執行復雜的數據聚合任務。Map-Reduce 操作由兩個階段組成&#xff1a;Map 階段和 Reduce 階段。 基本語法 在 MongoDB 中&#xff0c;可以使用 db.collection.mapReduce() 方法執行…

IsoBench:多模態基礎模型性能的基準測試與優化

隨著多模態基礎模型的快速發展&#xff0c;如何準確評估這些模型在不同輸入模態下的性能成為了一個重要課題。本文提出了IsoBench&#xff0c;一個基準數據集&#xff0c;旨在通過提供多種同構&#xff08;isomorphic&#xff09;表示形式的問題&#xff0c;來測試和評估多模態…

算法(十三)回溯算法---N皇后問題

文章目錄 算法概念經典例子 - N皇后問題什么是N皇后問題&#xff1f;實現思路 算法概念 回溯算法是類似枚舉的深度優先搜索嘗試過程&#xff0c;主要是再搜索嘗試中尋找問題的解&#xff0c;當發生不滿足求解條件時&#xff0c;就會”回溯“返回&#xff08;也就是遞歸返回&am…