后端之路——登錄校驗前言(Cookie\ Session\ JWT令牌)

前言:Servlet

【登錄校驗】這個功能技術的基礎是【會話技術】,那么在講【會話技術】的時候必然要談到【Cookie】和【Session】這兩個東西,那么在這之前必須要先講一下一個很重要但是很多人都會忽略的一個知識點:【Servlet

什么是Servlet?

????????Servlet是用java編寫的應用在服務器端的程序;對于它的定義,“廣義上”是一個個很大的【類】,“狹義上”是【接口】

.

Servlet容器是什么?

????????我們經常聽說的Tomcat、Weblogic......這些都是各種【Servlet容器】,而【Servlet容器】就是Servlet的運行環境,也可以理解是Servlet的引擎,為請求和響應的這些操作提供網絡服務。

????????那么我們知道,我們運行網絡服務的時候都要啟動Tomcat服務器,Tomcat來解析處理【請求】、【響應】,并處理成報文信息,但是這些服務器的缺點是底層代碼寫死了,很不靈活,而且有時處理完的數據格式也不夠規范;那么這時候就誕生了Servlet,它被用來“擴展服務器的性能”,它能夠靈活的處理請求、響應數據并以規范形式返回。

????????那么說回Servlet,其實最簡單最簡單的理解,就是一個很大很規范的【類】,它里面包含了很多其他【子類】(準確來說是接口),這些子類包括:CookieSessionHttpServletRequestHttpServletResponse、ServletConfig、ServletContext......

????????那么這些【子類】里也寫好了很詳細、規范的各種處理網絡服務的方法,當我們需要處理一些網絡服務邏輯的時候,就需要調用Servlet里的【子類】的【實例化對象】的【方法】

????????打個比方:處理前端客戶端發送請求的數據并生成對應的請求頭報文時,就需要調用【HttpServletRequest】的實例化對象的方法;? 處理服務器端返回回去的響應頭報文的時候,就需要調用【HttpServletResponse】的實例化對象的方法......等等

那么現在我們重新來看一下(B/S架構)瀏覽器客戶端與服務器端傳輸的流程:

1、瀏覽器客戶端發送請求到服務器端

2、服務器端接收到信息,交給Servlet

3、Servlet(通過調用里面的一些子類的方法)處理邏輯,然后生成響應信息,給回服務器

4、服務器將響應結果返回瀏覽器客戶端

一、會話技術

1、何為會話?

瀏覽器與服務器之間的一次連接就是一次會話

2、會話跟蹤

【會話跟蹤】就是:識別多個請求是否來自于同一個瀏覽器,然后在同一個瀏覽器的多個請求之間共享數據

3、會話跟蹤方案:

瀏覽器與服務器之間的交互使用的是【http】協議,但是【http】協議是無狀態的,也就是所有請求都是相互獨立的,并不能在多個請求之間共享數據

那么就有了這么幾種【會話跟蹤技術】:

1、客戶端會話跟蹤技術:Cookie

.

2、服務端會話跟蹤技術:Session

3、token令牌技術:JWT

這里不講解HTTP是啥,這里有一篇講的比較詳細:HTTP 協議詳解(史上最全)-CSDN博客

HTTP協議里的【請求頭】和【響應頭】的文章:Request Headers 和Response Headers——請求頭和響應頭-CSDN博客

只需要知道HTTP協議是一個瀏覽器與服務器聯系傳輸數據的超文本傳輸協議,它兩規定了一種傳輸數據的格式,然后里面有【響應報文Response Headers】和【請求報文Request Headers】這兩部分,下面是簡單講解:

請求報文Request Headers】:

前端通過【瀏覽器/客戶端】發送請求傳給【服務器】的數據信息

一個【請求報文Request Headers】里包括了【請求行】【請求頭】【請求體】

【請求體】就是前端傳過來的具體的數據信息

【請求頭】是服務器獲取客戶端信息的一些依據(用什么格式獲取?從哪個地址獲取?哪個瀏覽器發的?......)

響應頭報文Reponse Headers】:

【服務器】返回給【瀏覽器/客戶端】的響應數據信息

一樣,一個【響應報文Response Headers】里也包括了【響應行】【響應頭】【響應體】

【響應體】就是針對前端發來的請求數據而相應回去的具體數據值

【響應頭】包含了服務器的響應訊息,如http版本,壓縮方式,響應文件類型,文件編碼等

(1)Cookie技術(Cookie是一個Servlet里的“子類”)

雖然每個請求和響應之間的Http協議是獨立的,但是Http協議的【請求頭】和【響應頭】支持攜帶【Cookie】這個信息,那多個請求間就可以通過Cookie這個標識來獲取用戶信息數據

Cookie簡單說:就是存放在客戶端(瀏覽器)】的會話信息

—— Cookie是通過在【請求報文Request Headers】里的【請求頭】處傳遞的

—— 傳遞關系是:【客戶端(瀏覽器)——傳Cookie——>服務器

—— Set-Cookie是通過【響應報文Response Headers】里的【響應頭】處傳遞的

—— 傳遞關系是:【服務器——返回Set-Cookie——>客戶端(瀏覽器)

簡單用代碼直觀一點展示Cookie和Set-Cookie:(切記別記憶這些代碼,簡單了解即可)

Set-Cookie:

【HttpServletResponse】這個接口的實現類是專門設置【響應報文】信息的(切記:要導入的包一定要選這個【javax.servlet.http】)

.

然后【HttpServletResponse】的實現類對象的【.addCookie( )】方法能設置一個Cookie的值,需要往里面傳一個【Cookie對象】(切記:這個【Cookie對象】對應的類型必須也是【javax.servlet.http】)

.

最后【Cookie對象】里數據形式是“鍵值對Key=value”:【name=value】,所以要傳一個name參數、一個value值,分別代表 “鍵” 和 “值”

/*** 模擬【服務器】設置【用戶的Cookie】的操作* @param response* @return*/
@GetMapping("/setCookie")
public Result setCookie(HttpServletResponse response){//調用這個響應方法就能設置一個Cookie值,Cookie對象里是【鍵值對】信息:name=valueresponse.addCookie(new javax.servlet.http.Cookie("userName","岑梓銘"));return Result.success();
}

怎么看效果?

1、首先輸入網址,千萬先別回車

2、摁F12打開網頁檢查,然后再在網址那回車,就會看到一個網絡響應

3、單擊它,然后就能在【響應報文Response Header】處看到【Set-Cookie】

Cookie:

【HttpServletRequest】這個接口的實現類是專門設置【請求報文】信息的(切記:要導入的包一定要選這個【javax.servlet.http】)

.

然后【HttpServletRequest】的實現類對象的【.getCookies( )】方法能返回所有Cookie的值,返回值是一個數組;需要用一個【Cookie對象類型的數組】接收(切記:這個【Cookie對象】類型對應的類型必須也是【javax.servlet.http】)

.

最后【Cookie對象】里數據形式是“鍵值對Key=value”:【name=value】,所以要獲取Cookie數組里每一個Cookie的 “鍵”,就要調用【Cookie對象】的【.getName( )】方法

@GetMapping("/getCookie")
public Result getCookie(HttpServletRequest request){//發送請求后,獲取返回的【所有的Cookies】javax.servlet.http.Cookie[] cookies = request.getCookies();//遍歷所有Cookie,如果有對應這個【鍵(name)】的,就返回對應的【值(value)】for(javax.servlet.http.Cookie cookie : cookies){if(cookie.getName().equals( "userName" )){System.out.println("userName: " + "【" + cookie.getValue() + "】");}}return Result.success();
}

?怎么看效果?還是一樣

1、首先輸入網址,千萬先別回車

2、摁F12打開網頁檢查,然后再在網址那回車,就會看到一個網絡響應

3、單擊它,然后就能在【響應報文Response Header】處看到【Set-Cookie】

缺點

1、移動端環境不是瀏覽器,瀏覽器才有Cookie這玩意

.

2、用戶可以隨意自己設置禁用Cookie,會用電腦的應該不用我解釋,瀏覽器設置那里有

.

3、Cookie不能跨域(跨域就是【協議、IP/域名、端口】至少其中一樣不一樣,就是兩個域,就存在跨域訪問,那么我們都知道前端、后端是分別部署到兩個不同的服務器的,不同服務器的地址肯定是不一樣的,瀏覽器在發請求、返回響應時必然會要訪問前端和后端的兩個服務器,就會跨域)

總結

(2)Session技術(Session也是Servlet里的一個“子類”)

Session的本質其實就是對Cookie的優化,是存放在【服務器端】的會話信息

為什么說是Cookie的優化?因為它的邏輯其實是這樣:

????????首先瀏覽器發請求,產生一個會話,然后服務器這邊就立刻產生一個【Session會話信息】和一個對應這個Session會話信息的【sessionId】,然后把【Session會話信息】存在服務器,只會把【sessionId】存進Cookie,通過Set-Cookie響應回給瀏覽器

。。

????????然后下次瀏覽器再次發送請求想獲取這個【Session會話信息】的時候,傳遞過去的是【裝著sessionId的Cookie】,然后服務器檢查Cookie里的【sessionId】,再到session里找有沒有對應這個【sessionId】的【Session會話信息】,找到了的話,把【sessionId】和【Session會話信息】一起塞進【Cookie】返回給瀏覽器

模擬服務器【保存session】并【生成sessionId】的邏輯
/*** 模擬【服務器端】生成并響應回【session】的操作* @param session* @return*/
@GetMapping("/setSession")
public Result setSession(HttpSession session){//打印一下當前session的哈希碼值,這個哈希碼值代表指向了哪一個session會話,是【整數】//但是注意區分,這個不是sessionId,sessionId是HttpSession對象的唯一標識符,是【字符串】log.info("session_hashCode: {}",session.hashCode());//調用這個方法可以往session會話里存入一個數據,然后對應生成一個sessionID并塞進Cookie里session.setAttribute("LoginName","岑梓銘");return Result.success();
}

模擬瀏覽器通過sessionId【接收session信息】的邏輯
/*** 模擬【瀏覽器】發請求后獲得服務器生成的【session】的操作* @param request* @return*/
@GetMapping("/getSession")
public Result getSession(HttpServletRequest request){//調用HttpServletRequest對象的getSession()方法可以獲取到session會話對象HttpSession session = request.getSession();//打印一下當前session的哈希碼值,這個哈希碼值代表指向了哪一個session會話,是【整數】log.info("session_hashCode: {}",session.hashCode());//Session的getAttribute方法,里面傳入“鍵”參數,就能返回對應的seesion會話對象里的具體值//邏輯是瀏覽器這邊Cookie里只有sessionId,然后通過Session的getAttribute方法把Cookie里的sessionId給到服務器端//最終經過服務器檢測sessionId,然后將session會話里對應“userName”的會話具體數據再塞進Cookie,返回給瀏覽器Object userInfo = session.getAttribute("LoginName");log.info("userInfo: {}",userInfo);return Result.success(userInfo);
}

?缺點

1、服務器集群情況下(也就是連接多個服務器的情況下),不同的服務器之間存著不同的會話信息,那就算瀏覽器的Cookie里有sessionId,那第二臺服務器那里能靠第一臺服務器seesion的 “鑰匙” 來 “開“ 第二臺服務器seesion的 “大門” 呢?

.

2、session會話信息都存在服務器,隨著瀏覽器請求增多,服務器內存越來越不夠用

.

3、既然它還是基于Cookie優化而來的,那必然也繼承了Cookie的缺點

總結

(3)JWT令牌技術

——概念:

JWT,全稱:【Json?Web?Token】,簡單來說就是一長串帶有【數字簽名、簽名算法、具體自定義信息......等等】json字符串,每一次請求響應都會帶著它,通過計算來校驗、得出其中的身份信息

一個JWT字符串主要包括三大部分:

????????第一部分:Header(頭),記錄令牌類型、名算法等。例如:{"alg":"HS256","type":"JWT"}

????????第二部分:Payload(有效載荷),攜帶一些自定義信息、默認信息等。例如:{"id":"1","username":"Tom"}

????????第三部分:Siqnature(簽名),防止Token被篡改、確保安全性。將header、payload,并加入指定秘鑰,通過指定簽名算法計算而來。

而組成這個字符串的原理是:

1、前面兩部分是【Base64編碼】,是一種由【A-Z? a-z? 1-9? 還有/】組成的來表示二進制數據的編碼

2、最后一部分那一段是根據前面指定的一種【簽名算法】計算后得到的編碼

應用場景:

其實很簡單,流程就是:

1、瀏覽器發送請求到服務器

2、服務器攔截請求,查看有沒有token?沒有就拒絕訪問數據,并生成一個JWT令牌

3、下一次再來檢查到有JWT令牌了,那就校驗JWT令牌對不對,不對就拒絕訪問;對就開放訪問權限。

生成JWT令牌的方法:
1、引入依賴

在pom.xml文件引入下面依賴

<!-- JWT令牌 -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

注意,如果點了右上角的【maven刷新】按鈕只后還是爆紅,又可能只是連接中央庫下載安裝這個依賴包的時候網絡不好,畢竟這些依賴都是在國外的公司的中央庫,那么控制臺那會有一個 “藍色” 的提示——“嘗試使用 -U 標記(強制更新快照)運行 Maven導入”,直接點它讓Maven幫我們換個方案下載安裝就行了

2、在Test類測試一下生成JWT令牌

只需要記住6步:

1、先設置一個哈希表集合,因為jwt令牌的【有效信息部分】要用【哈希表集合類型】接收

2、創建一個jwt的方法是【Jwts.builder( )】

3、一個Jwt令牌的第一部分是指定 “簽名算法類型”“簽名密鑰”;那么【.signWith( )方法】就是設置jwt令牌第一部分。以我個人理解,“簽名算法類型” 就是指根據不同類型的不同算法,“簽名密鑰” 就是以你自定義輸入的一串字符串作為一個 “密鑰”,用你的這個 “簽名密鑰”?才能在解析jwt令牌時知道你要解析的是哪一個(至于“簽名算法類型”具體哪些類型有啥區別我也不知道,盡量先都用HS256這個類型就行)

4、一個Jwt令牌的第二部分是【有效荷載】,也就是用戶的一些【有效信息部分】,【Jwts.addClaims( )】方法則是在創建一個jwt對象之后接收這個【有效信息部分】的方法,接收【哈希表集合】類型數據

5、jwt令牌要有個【有效時間】,就跟你們平時登錄時的驗證碼一樣,不然的話沒時間限制那不是留夠了時間給黑客破解嗎。【.setExiration( )】方法就是設置【有效時間】,需要接受的是Date時間類型(System.currentTimeMillis()是目前的系統時間,加一個有效時間期限就行)

6、jwt是一個對象,要用【.compact( )】方法才能轉化成【字符串】

@Test
void testGenJWT(){//先設置一個哈希表集合,因為jwt令牌的【有效信息部分】要用【哈希表集合類型】接收Map<String , Object> claims = new HashMap<>(); //值用Object因為可能是數字、可能是字符串claims.put("id",1);claims.put("name","岑梓銘");String jwt = Jwts.builder() //builder就是創建一個JWT令牌.signWith(SignatureAlgorithm.HS256,"yjtlwkbz") //設置【簽名算法的類型(比如HS256)】、【簽名內容(比如yjtlwkbz)】.addClaims(claims) //有效荷載部分,接收哈希表集合類型,存入用戶有效信息.setExpiration(new Date(System.currentTimeMillis() + 3600*1000)) //設置有效時間1h(3600秒 * 1000毫秒).compact(); //把結果生成字符串System.out.println(jwt);
}

然后提示幾點:

1、因為頂上的【@SpringBootTest】注解會影響整個項目,直接注釋了,然后點對應這個當前這個【@Test】測試方法運行最快

.

2、如果剛剛編寫生成jwt令牌代碼時爆紅爆錯,檢查這幾個問題:

—— 報錯classNotFoundException的下載jaxb-api依賴,2.1版本(版本別填錯了)

—— 使用Base64編碼字符串長度至少為43位,位數報錯的可以把 “簽名內容” 改成任意的大于等于43位的字符串(比如我代碼里的"yjtlwkbz"改成"ahjahsdgaysdgkuywdgjwdbasbcjhcjasyasgkjjsh")

3、還有有的人可能會出現【test】包下的test類(class文件)全變成java文件了,沒法運行,右鍵也不能新建class類文件,那可能是IDE出了點問題,清楚IDE緩存再重新啟動一次就行,見下圖

然后運行完成后,我們把控制臺生成的【jwt令牌】復制,到這個網站可以查看解析我們的【jwt令牌】的信息:JSON Web Tokens - jwt.io

解析JWT令牌的方法

更簡單,三步:

1、【Jwts.parser( )】方法解析jwt令牌

2、【.setSigningKey( )】方法就是根據你前面生成jwt令牌時的那個【簽名密鑰】來 “打開解密大門”

3、【.parseClaimsJws( )】把剛剛生成的【jwt令牌】整個塞進去就能被解析了

注意,別選成【.parseClaimsJwt( )】了,這兩是兩個東西,選下圖這個

4、【.getBody( )】能夠獲取出【有效荷載】部分那些具體信息,并封裝在一個Claims類型對象

@Test
void testGetJWT(){Claims claims = Jwts.parser().setSigningKey("yjtlwkbz")  //對應生成jwt的.signWith(SignatureAlgorithm.HS256,"yjtlwkbz")那個密鑰//對應剛剛運行生成的jwt令牌.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bKR5qKT6ZOtIiwiaWQiOjEsImV4cCI6MTcyMDQwOTg1Nn0.OmpQBJoP50BjjPnItLBGCmhgAVTcDzYGsTBMT7qohoE").getBody(); //獲取有效荷載部分System.out.println(claims);
}

注意幾點:

1、有效信息最后要用一個Claims對象來接收

2、一個jwt令牌有時效和使用次效,你如果超過了你設置的失效期限、或者已經運行執行了一次解析jwt令牌,那么這串jwt令牌就作廢了,需要你再次運行【生成jwt令牌】,然后再運行【解析jwt令牌】獲取信息,否則會報錯

3、【.parseClaimsJws( )】別寫成了【.parseClaimsJwt( )】

二、利用jwt令牌技術校驗身份

現在我們學完了最先進的jwt令牌技術,那么就來實踐一下如何運用它。

1、先為了前后端請求響應方便,封裝好一個jwt令牌工具類

很簡單,我們前面已經知道怎么【生成】和【解析】jwt令牌了,那么在封裝工具類里只要改幾點:

/

1、【生成jwt令牌】的時候首先要接收一個前端傳過來的裝著用戶有效信息的【哈希表集合】參數;并最后要把生成的令牌字符串return出去

.

2、【解析jwt令牌】的時候需要接收生成的jwt字符串;并把解析獲得【有效荷載信息】return回前端

package com.czm.tliaswebmanagement.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;
import java.util.HashMap;
import java.util.Map;//別忘了加這個注解,讓類放入IOC容器
@Component
public class JwtUtils {private static String signKey = "yjtlwkbz"; //定義【簽名密鑰】是“yjtlwkbz”private static Long time = (long)60*5 * 1000; //定義有效時間是5分鐘/*** 接收前端有效信息,生成jwt令牌并返回給前端* @param claims* @return*/public String generateJWT(Map<String,Object> claims){String jwt = Jwts.builder() //builder就是創建一個JWT令牌.signWith(SignatureAlgorithm.HS256,signKey) //設置【簽名算法的類型】、【簽名內容】.addClaims(claims) //有效荷載部分,接收哈希表集合類型,存入用戶有效信息.setExpiration(new Date(System.currentTimeMillis() + time)) //設置有效時間.compact(); //把結果生成字符串return jwt;}/*** 接收前端傳來的jwt令牌,解析并返回有效荷載* @param jwt* @return*/public Claims parseJWT(String jwt){Claims claims = Jwts.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();return claims;}
}

2、然后完成登錄接口(三層架構)代碼編寫

1、首先根據接口文檔規定,來確定前端傳入的是什么格式數據

比如這個文檔,以它為例子,那么確定前端傳入【JSON格式】的【用戶登錄信息】,那么就要用一個Emp對象(我前幾篇一直用的案例,員工對象)來接收這些參數值,然后用【@RequestBody】解析JSON成對象。然后post請求跟接口是“/login”,那就【@PostMapping("/login")】

(contrller)

2、第二步,在controller層調用service、并把剛剛解析的參數Emp傳給service,service調用mapping進行sql查詢,根據這個【用戶登錄信息】參數查詢完數據庫之后返回結果,再一級一級返回controller,老生常談的流程我就不細說了。

(controllerr)

(service )

(mapping)????????

3、然后在controller層再用一個【新的Emp對象】接收【查詢完返回的結果】,如果查詢到結果就說明數據庫有這個賬戶,那么調用【JWT工具類】為這個賬戶【生成一個jwt令牌】(生成jwt的邏輯,在JWT工具類已經幫我們做好了,我們只需要傳一個【裝有用戶信息】的【Map哈希表集合類的參數】給JWT工具類就行了)

4、最后,在查詢到賬戶的情況下,將生成含有用戶信息的JWT令牌返回給前端即可;如果查不到信息,就說明賬戶密碼有誤,查無此人,那就直接返回失敗。

controller的完整代碼:(其他的層的就不展示了)

package com.czm.tliaswebmanagement.controller;import com.czm.tliaswebmanagement.pojo.Emp;
import com.czm.tliaswebmanagement.pojo.Result;
import com.czm.tliaswebmanagement.service.EmpService;
import com.czm.tliaswebmanagement.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@Slf4j
//@RequestMapping("/emps")
@RestController
public class EmpController {@Autowiredprivate EmpService empService;//獲取JWT令牌工具類@Autowiredprivate JwtUtils jwtUtils;/*** 登錄接口*/@PostMapping("/login")public Result login(@RequestBody Emp emp){log.info("傳過來的員工賬號密碼信息:{}",emp);//先調用service查找數據庫有無此賬戶Emp e = empService.login(emp);//判斷能否根據用戶名、密碼在數據庫查到此人//有的話,生成屬于它的令牌,并返回給他if(e != null){//因為生成jwt令牌需要的是【哈希表集合】類型,所以用一個【哈希表集合】裝查到的員工信息Map<String , Object> claims = new HashMap<>();//這里經過service、mapper查詢回來的員工信息e,獲取出他的id、name、username作為有效荷載信息claims.put("id",e.getId());claims.put("name",e.getName());claims.put("username",e.getUsername());//調用jwt工具類生成jwt方法獲取jwt令牌String jwt = jwtUtils.generateJWT(claims);//然后把jwt令牌返回給前端return Result.success(jwt);}//那么如果數據庫都沒查到這個賬戶,就說明賬號密碼輸入錯誤,返回錯誤就行了return Result.error("登陸失敗,查無此人");}
}

然后我要解釋一下這個jwt令牌到底在哪里傳輸

就在一個叫【token的玩意里存著,你可以理解為【token是一張磁卡,然后?jwt?就是類似這個磁卡的信號信息,你用【token這個磁卡刷門禁、刷刷卡機的時候,把 jwt 信息傳過去驗證。

然后這個【token可以放請求體、也可以是請求頭,不過一般都是放請求頭

那么現在前端只要登陸成功,就已經能獲取到后端為之生成的jwt令牌了,現在只需要下次再攜帶這個jwt令牌發送請求,后端就可針對這個令牌進行判斷:是否給這個用戶放行使用軟件、網頁了,那么這就涉及到【過濾器filter】和【攔截器Interceptor】,下一篇再講

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

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

相關文章

Oracle PL/SQL 循環批量執行存儲過程

1. 查詢存儲過程 根據數據字典USER_OBJECTS查詢出所有存儲過程。 2. 動態拼接字符串&#xff08;參數等&#xff09; 根據數據字典USER_ARGUMENTS動態拼接參數。 3. 動態執行 利用EXECUTE IMMEDIATE動態執行無名塊。 4. 輸出執行信息 利用DBMS_OUTPUT.PUT_LINE輸出執行成功與…

Android Gradle 開發與應用 (十): Gradle 腳本最佳實踐

目錄 1. 使用Gradle Kotlin DSL 1.1 什么是Gradle Kotlin DSL 1.2 遷移到Kotlin DSL 1.3 優勢分析 2. 優化依賴管理 2.1 使用依賴版本管理文件 2.2 使用依賴分組 3. 合理使用Gradle插件 3.1 官方插件和自定義插件 3.2 插件管理的最佳實踐 4. 任務配置優化 4.1 使用…

Oracle 19c 統一審計表清理

zabbix 收到SYSAUX表空間告警超過90%告警&#xff0c;最后面給出的清理方法只適合ORACLE 統一審計表的清理&#xff0c;傳統審計表的清理SYS.AUD$不適合&#xff0c;請注意。 SQL> Col tablespace_name for a30 Col used_pct for a10 Set line 120 pages 120 select total.…

STM32實戰篇:閃燈 × 流水燈 × 蜂鳴器

IO引腳初始化 即開展某項活動之前所做的準備工作&#xff0c;對于一個IO引腳來說&#xff0c;在使用它之前必須要做一些參數配置&#xff08;例如&#xff1a;選擇工作模式、速率&#xff09;的工作&#xff08;即IO引腳的初始化&#xff09;。 IO引腳初始化流程 1、使能IO引…

LED燈的呼吸功能

"呼吸功能"通常是指 LED 燈的一種工作模式&#xff0c;它模擬人類的呼吸節奏&#xff0c;即 LED 燈的亮度會周期性地逐漸增強然后逐漸減弱&#xff0c;給人一種 LED 在"呼吸"的感覺。這種效果通常用于指示設備的狀態或者簡單地作為裝飾效果。&#xff08;就…

Spring Boot Security自定義AuthenticationProvider

以下是一個簡單的示例&#xff0c;展示如何使用AuthenticationProvider自定義身份驗證。首先&#xff0c;創建一個繼承自標準AuthenticationProvider的類&#xff0c;并實現authenticate方法。 import com.kamier.security.web.service.MyUser; import org.springframework.se…

【Adobe】Photoshop圖層的使用

Adobe Photoshop(簡稱PS)中的圖層是圖像處理中一個核心概念,它允許用戶以堆疊的方式組織圖像的不同部分,從而實現對圖像的復雜編輯和處理而不影響原始圖像。以下是關于Adobe Photoshop圖層的詳細介紹: 一、圖層的定義 圖層就像是透明的紙張,你可以在上面繪制、添加圖像…

YOLOv10改進 | EIoU、SIoU、WIoU、DIoU、FocusIoU等二十余種損失函數

一、本文介紹 這篇文章介紹了YOLOv10的重大改進&#xff0c;特別是在損失函數方面的創新。它不僅包括了多種IoU損失函數的改進和變體&#xff0c;如SIoU、WIoU、GIoU、DIoU、EIOU、CIoU&#xff0c;還融合了“Focus”思想&#xff0c;創造了一系列新的損失函數。這些組合形式的…

Android Init Language自學筆記

Android Init Language由五個元素組成&#xff1a;Acttions、Commands、Services、Options和Imports。 Actions和Services隱式聲明了一個新的section。所以的Commands和Options都屬于最近聲明的section。 Services具有唯一的名稱&#xff0c;如果重名會報錯。 Actions Acti…

解決Spring Boot中的高可用性設計

解決Spring Boot中的高可用性設計 大家好&#xff0c;我是微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 1. 高可用性設計概述 1.1 什么是高可用性&#xff1f; 高可用性指系統在面對各種故障和異常情況時&#xff0c;仍…

獨立開發者系列(22)——API調試工具apifox的使用

接口的邏輯已經實現&#xff0c;需要對外發布接口&#xff0c;而發布接口的時候&#xff0c;我們需要能自己簡單調試接口。當然&#xff0c;其實自己也可以寫簡單的代碼調試自己的接口&#xff0c;因為其實就是簡單的request請求或者curl庫讀取&#xff0c;調整請求方式get或者…

如果MySQL出現 “Too many connections“ 錯誤,該如何解決?

當你想要連接MySQL時出現"Too many connections" 報錯的情況下&#xff0c;該如何解決才能如愿以償呢&#xff1f;都是哥們兒&#xff0c;就教你兩招吧&#xff01; 1.不想重啟數據庫的情況下 你可以嘗試采取以下方法來解決&#xff1a; 增加連接數限制&#xff1a…

RxJava學習記錄

文章目錄 1. 總覽1.1 基本原理1.2 導入包和依賴 2. 操作符2.1 創建操作符2.2 轉換操作符2.3 組合操作符2.4 功能操作符 1. 總覽 1.1 基本原理 參考文獻 構建流&#xff1a;每一步操作都會生成一個新的Observable節點(沒錯&#xff0c;包括ObserveOn和SubscribeOn線程變換操作…

asp.netWebForm(.netFramework) CSRF漏洞

asp.netWebForm(.netFramework) CSRF漏洞 CSRF&#xff08;Cross-Site Request Forgery&#xff09;跨站請求偽造是一種常見的 Web 應用程序安全漏 洞&#xff0c;攻擊者通過誘使已認證用戶在受信任的網站上執行惡意操作&#xff0c;從而利用用戶的身份 執行未經授權的操作。攻…

echarts實現3D餅圖

先看下最終效果 實現思路 使用echarts-gl的曲面圖&#xff08;surface&#xff09;類型 通過parametric繪制曲面參數實現3D效果 代碼實現 <template><div id"surfacePie"></div> </template> <script setup>import {onMounted} fro…

簡單的找到自己需要的flutter ui 模板

簡單的找到自己需要的flutter ui 模板 網站 https://flutterawesome.com/ 簡介 我原本以為會很難用 實際上不錯 很簡單 打開后界面類似于,右上角可以搜索 點擊view github 相當簡單 很oks

RabbitMq,通過prefetchCount限制消費并發數

1.問題:項目瓶頸,通過rabbitMq來異步上傳圖片,由于并發上傳的圖片過多導致阿里OSS異常, 解決方法:通過prefetchCount限制圖片上傳OSS的并發數量 2.定義消費者 Component AllArgsConstructor Slf4j public class ReceiveFaceImageEvent {private final UPloadService uploadSe…

【見刊通知】MVIPIT 2023機器視覺、圖像處理與影像技術國際會議

MVIPIT 2023&#xff1a;https://ieeexplore.ieee.org/xpl/conhome/10578343/proceeding 入庫Ei數據庫需等20-50天左右 第二屆會議征稿啟動&#xff08;MVIPIT 2024&#xff09; The 2nd International Conference on Machine Vision, Image Processing & Imaging Techn…

MacOS和Windows中怎么安裝Redis

希望文章能給到你啟發和靈感&#xff5e; 如果覺得文章對你有幫助的話&#xff0c;點贊 關注 收藏 支持一下博主吧&#xff5e; 閱讀指南 開篇說明一、基礎環境說明1.1 硬件環境1.2 軟件環境 二、MacOS中Redis的安裝2.1 HomeBrew 安裝&#xff08;推薦&#xff09;2.2 通過官方…

70.WEB滲透測試-信息收集- WAF、框架組件識別(10)

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 內容參考于&#xff1a; 易錦網校會員專享課 上一個內容&#xff1a;69.WEB滲透測試-信息收集- WAF、框架組件識別&#xff08;9&#xff09; 關于waf相應的識…