Springboot 手搓 后端 滑塊驗證碼生成

目錄

一、效果演示

二、后端滑塊驗證碼生成思路

三、原理解析

四、核心代碼拿走


滑塊驗證碼react前端實現,見我的這篇博客:前端 React 彈窗式 滑動驗證碼實現_react中使用阿里云滑塊驗證碼2.0前端接入及相關視覺-CSDN博客

一、效果演示

生成的案例圖片:

視頻演示:

滑塊驗證碼演示

二、后端滑塊驗證碼生成思路

1、后端需要生成對應的兩個圖片(拼圖圖片和拼圖背景圖片,圖片內存盡量小一點)和對應位置(x和y, 等高拼圖只需要記錄x即可);

2、驗證碼生成服務,生成唯一的標識uuid(可考慮雪花算法生成),將生成圖片生成后得到的位置信息即x(非登高拼圖x和y)記錄到緩存中,建議使用redis存儲,即使分布式也能使用;

3、將驗證碼數據返回給前端,格式參考如下:

三、原理解析

要想生成拼圖形狀的拼圖,我們需要運用到一些數學知識,核心代碼如下:

通過?圓的標準方程 (x-a)2+(y-b)2=r2,標識圓心(a,b),半徑為r的圓,>=的在外側,<的內側。

簡單來看就是這樣的一個模型:

 /*** 隨機生成拼圖圖輪廓數據** @param randomR1 圓點距離隨機值* @return 0和1,其中0表示沒有顏色,1有顏色*/private static int[][] createTemplateData(int randomR1) {// 拼圖輪廓數據int[][] data = new int[puzzleWidth][puzzleHeight];// 拼圖去掉凹凸的白色距離int xBlank = puzzleWidth - distance;int yBlank = puzzleHeight - distance;// 記錄圓心的位置值int topOrBottomX = puzzleWidth / 2;int leftOrRightY = puzzleHeight / 2;// 凹時對應的位置int topYOrLeftX = distance - randomR1 + radius;int rightX = puzzleWidth - topYOrLeftX;int bottomY = puzzleHeight - topYOrLeftX;// 凸時對應的位置int topYOrLeftXR = distance + randomR1 - radius;int rightXR = puzzleWidth - topYOrLeftXR;int bottomYR = puzzleHeight - topYOrLeftXR;double rPow = Math.pow(radius, 2);/* 隨機獲取判斷條件 */Random random = new Random();Integer[] randomCondition = new Integer[]{random.nextInt(3),random.nextInt(3),random.nextInt(3),random.nextInt(3)};/*計算需要的拼圖輪廓(方塊和凹凸),用二維數組來表示,二維數組有兩張值,0和1,其中0表示沒有顏色,1有顏色圓的標準方程 (x-a)2+(y-b)2=r2,標識圓心(a,b),半徑為r的圓*/for (int i = 0; i < puzzleWidth; i++) {for (int j = 0; j < puzzleHeight; j++) {/* 凹時對應的圓點 */// 頂部的圓心位置為(puzzleWidth / 2, topYOrLeftX)double top = Math.pow(i - topOrBottomX, 2) + Math.pow(j - topYOrLeftX, 2);// 底部的圓心位置為(puzzleWidth / 2, puzzleHeight - topYOrLeftX)double bottom = Math.pow(i - topOrBottomX, 2) + Math.pow(j - bottomY, 2);// 左側的圓心位置為(topYOrLeftX, puzzleHeight / 2)double left = Math.pow(i - topYOrLeftX, 2) + Math.pow(j - leftOrRightY, 2);// 右側的圓心位置為(puzzleWidth - topYOrLeftX, puzzleHeight / 2)double right = Math.pow(i - rightX, 2) + Math.pow(j - leftOrRightY, 2);/* 凸時對應的圓點 */// 頂部的圓心位置為(puzzleWidth / 2, topYOrLeftXR)double topR = Math.pow(i - topOrBottomX, 2) + Math.pow(j - topYOrLeftXR, 2);// 底部的圓心位置為(puzzleWidth / 2, puzzleHeight - topYOrLeftXR)double bottomR = Math.pow(i - topOrBottomX, 2) + Math.pow(j - bottomYR, 2);// 左側的圓心位置為(topYOrLeftXR, puzzleHeight / 2)double leftR = Math.pow(i - topYOrLeftXR, 2) + Math.pow(j - leftOrRightY, 2);// 右側的圓心位置為(puzzleWidth - topYOrLeftXR, puzzleHeight / 2)double rightR = Math.pow(i - rightXR, 2) + Math.pow(j - leftOrRightY, 2);/* 隨機獲取條件 */Boolean[][] conditions = new Boolean[][]{new Boolean[]{(j <= distance && topR >= rPow),(j <= distance || top <= rPow),(j <= distance)},new Boolean[]{(j >= yBlank && bottomR >= rPow),(j >= yBlank || bottom <= rPow),(j >= yBlank)},new Boolean[]{(i <= distance && leftR >= rPow),(i <= distance || left <= rPow),(i <= distance)},new Boolean[]{(i >= xBlank && rightR >= rPow),(i >= xBlank || right <= rPow),(i >= xBlank)}};boolean hide = false;for (int c = 0; c < randomCondition.length; c++) {if (conditions[c][randomCondition[c]]) {hide = true;break;}}if (hide) {// 不顯示的像素data[i][j] = 0;} else {data[i][j] = 1;}}}return data;}

繪制好需要截取的數據位置后,再來進行剪切:

 /*** 裁剪拼圖** @param bgImg             - 原圖規范大小之后的大圖* @param puzzleImg         - 小圖* @param slideTemplateData - 拼圖輪廓數據* @param x                 - 坐標x* @param y                 - 坐標y*/private static void cutByTemplate(BufferedImage bgImg, BufferedImage puzzleImg, int[][] slideTemplateData, int x, int y) {int[][] matrix = new int[3][3];int[] values = new int[9];// 虛假的x坐標int fakeX = getRandomFakeX(x);// 創建shape區域,即原圖摳圖區域模糊和摳出小圖/*遍歷小圖輪廓數據,創建shape區域。即原圖摳圖處模糊和摳出小圖*/for (int i = 0; i < puzzleImg.getWidth(); i++) {for (int j = 0; j < puzzleImg.getHeight(); j++) {// 獲取大圖中對應位置變色int rgb_ori = bgImg.getRGB(x + i, y + j);// 0和1,其中0表示沒有顏色,1有顏色int rgb = slideTemplateData[i][j];if (rgb == 1) {// 設置小圖中對應位置變色puzzleImg.setRGB(i, j, rgb_ori);// 大圖摳圖區域高斯模糊readPixel(bgImg, x + i, y + j, values);fillMatrix(matrix, values);bgImg.setRGB(x + i, y + j, avgMatrix(matrix));// 摳虛假圖readPixel(bgImg, fakeX + i, y + j, values);fillMatrix(matrix, values);bgImg.setRGB(fakeX + i, y + j, avgMatrix(matrix));} else {// 這里把背景設為透明puzzleImg.setRGB(i, j, rgb_ori & 0x00ffffff);}}}}

四、核心代碼拿走

SliderCaptchaUtil:

package com.xloda.common.tool.captcha.util;import com.xloda.common.tool.captcha.constant.SliderCaptchaConfig;
import com.xloda.common.tool.captcha.pojo.SliderCaptcha;import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;/*** @author Dragon Wu* @since 2025/04/23 10:52* 滑塊驗證碼生成器*/public class SliderCaptchaUtil implements SliderCaptchaConfig {/*** 生成滑塊驗證碼** @param bgImg     1. 傳入隨機背景圖* @param accordant 是否生成登高拼圖* @return SliderCaptcha 驗證碼結果* @throws IOException IO異常*/public static SliderCaptcha generateCaptcha(BufferedImage bgImg, boolean accordant) throws IOException {// 2. 隨機生成離左上角的(X,Y)坐標,上限為 [width-puzzleWidth, height-puzzleHeight]。最好離大圖左邊遠一點,上限不要緊挨著大圖邊界Random random = new Random();// X范圍:[puzzleWidth, width - puzzleWidth)int x = random.nextInt(width - 2 * puzzleWidth) + puzzleWidth;// Y范圍:[puzzleHeight, height - puzzleHeight)int y = random.nextInt(height - 2 * puzzleHeight) + puzzleHeight;// 3. 創建拼圖圖像BufferedImage puzzleImg = new BufferedImage(puzzleWidth, puzzleHeight, BufferedImage.TYPE_4BYTE_ABGR);// 4. 隨機獲取位置數據int randomR1 = getRandomR1();// 5. 隨機生成拼圖輪廓數據int[][] slideTemplateData = createTemplateData(randomR1);// 6. 從大圖中裁剪拼圖。摳原圖,裁剪拼圖cutByTemplate(bgImg, puzzleImg, slideTemplateData, x, y);// 7. 給拼圖加邊框puzzleImg = ImageUtil.addBorderWithOutline(puzzleImg, borderSize, Color.white);// 8. 判斷是否為登高拼圖if (accordant) {puzzleImg = reshapeAccordant(puzzleImg, y);return new SliderCaptcha(ImageUtil.toBase64(bgImg),ImageUtil.toBase64(puzzleImg), x);}// 非登高拼圖,記錄x和yreturn new SliderCaptcha(ImageUtil.toBase64(bgImg),ImageUtil.toBase64(puzzleImg), x, y);}// 隨機獲取小圓距離點private static int getRandomR1() {Integer[] r1List = new Integer[]{radius * 3 / 2,radius,radius / 2,};int index = new Random().nextInt(r1List.length);return r1List[index];}/*** 隨機生成拼圖圖輪廓數據** @param randomR1 圓點距離隨機值* @return 0和1,其中0表示沒有顏色,1有顏色*/private static int[][] createTemplateData(int randomR1) {// 拼圖輪廓數據int[][] data = new int[puzzleWidth][puzzleHeight];// 拼圖去掉凹凸的白色距離int xBlank = puzzleWidth - distance;int yBlank = puzzleHeight - distance;// 記錄圓心的位置值int topOrBottomX = puzzleWidth / 2;int leftOrRightY = puzzleHeight / 2;// 凹時對應的位置int topYOrLeftX = distance - randomR1 + radius;int rightX = puzzleWidth - topYOrLeftX;int bottomY = puzzleHeight - topYOrLeftX;// 凸時對應的位置int topYOrLeftXR = distance + randomR1 - radius;int rightXR = puzzleWidth - topYOrLeftXR;int bottomYR = puzzleHeight - topYOrLeftXR;double rPow = Math.pow(radius, 2);/* 隨機獲取判斷條件 */Random random = new Random();Integer[] randomCondition = new Integer[]{random.nextInt(3),random.nextInt(3),random.nextInt(3),random.nextInt(3)};/*計算需要的拼圖輪廓(方塊和凹凸),用二維數組來表示,二維數組有兩張值,0和1,其中0表示沒有顏色,1有顏色圓的標準方程 (x-a)2+(y-b)2=r2,標識圓心(a,b),半徑為r的圓*/for (int i = 0; i < puzzleWidth; i++) {for (int j = 0; j < puzzleHeight; j++) {/* 凹時對應的圓點 */// 頂部的圓心位置為(puzzleWidth / 2, topYOrLeftX)double top = Math.pow(i - topOrBottomX, 2) + Math.pow(j - topYOrLeftX, 2);// 底部的圓心位置為(puzzleWidth / 2, puzzleHeight - topYOrLeftX)double bottom = Math.pow(i - topOrBottomX, 2) + Math.pow(j - bottomY, 2);// 左側的圓心位置為(topYOrLeftX, puzzleHeight / 2)double left = Math.pow(i - topYOrLeftX, 2) + Math.pow(j - leftOrRightY, 2);// 右側的圓心位置為(puzzleWidth - topYOrLeftX, puzzleHeight / 2)double right = Math.pow(i - rightX, 2) + Math.pow(j - leftOrRightY, 2);/* 凸時對應的圓點 */// 頂部的圓心位置為(puzzleWidth / 2, topYOrLeftXR)double topR = Math.pow(i - topOrBottomX, 2) + Math.pow(j - topYOrLeftXR, 2);// 底部的圓心位置為(puzzleWidth / 2, puzzleHeight - topYOrLeftXR)double bottomR = Math.pow(i - topOrBottomX, 2) + Math.pow(j - bottomYR, 2);// 左側的圓心位置為(topYOrLeftXR, puzzleHeight / 2)double leftR = Math.pow(i - topYOrLeftXR, 2) + Math.pow(j - leftOrRightY, 2);// 右側的圓心位置為(puzzleWidth - topYOrLeftXR, puzzleHeight / 2)double rightR = Math.pow(i - rightXR, 2) + Math.pow(j - leftOrRightY, 2);/* 隨機獲取條件 */Boolean[][] conditions = new Boolean[][]{new Boolean[]{(j <= distance && topR >= rPow),(j <= distance || top <= rPow),(j <= distance)},new Boolean[]{(j >= yBlank && bottomR >= rPow),(j >= yBlank || bottom <= rPow),(j >= yBlank)},new Boolean[]{(i <= distance && leftR >= rPow),(i <= distance || left <= rPow),(i <= distance)},new Boolean[]{(i >= xBlank && rightR >= rPow),(i >= xBlank || right <= rPow),(i >= xBlank)}};boolean hide = false;for (int c = 0; c < randomCondition.length; c++) {if (conditions[c][randomCondition[c]]) {hide = true;break;}}if (hide) {// 不顯示的像素data[i][j] = 0;} else {data[i][j] = 1;}}}return data;}/*** 裁剪拼圖** @param bgImg             - 原圖規范大小之后的大圖* @param puzzleImg         - 小圖* @param slideTemplateData - 拼圖輪廓數據* @param x                 - 坐標x* @param y                 - 坐標y*/private static void cutByTemplate(BufferedImage bgImg, BufferedImage puzzleImg, int[][] slideTemplateData, int x, int y) {int[][] matrix = new int[3][3];int[] values = new int[9];// 虛假的x坐標int fakeX = getRandomFakeX(x);// 創建shape區域,即原圖摳圖區域模糊和摳出小圖/*遍歷小圖輪廓數據,創建shape區域。即原圖摳圖處模糊和摳出小圖*/for (int i = 0; i < puzzleImg.getWidth(); i++) {for (int j = 0; j < puzzleImg.getHeight(); j++) {// 獲取大圖中對應位置變色int rgb_ori = bgImg.getRGB(x + i, y + j);// 0和1,其中0表示沒有顏色,1有顏色int rgb = slideTemplateData[i][j];if (rgb == 1) {// 設置小圖中對應位置變色puzzleImg.setRGB(i, j, rgb_ori);// 大圖摳圖區域高斯模糊readPixel(bgImg, x + i, y + j, values);fillMatrix(matrix, values);bgImg.setRGB(x + i, y + j, avgMatrix(matrix));// 摳虛假圖readPixel(bgImg, fakeX + i, y + j, values);fillMatrix(matrix, values);bgImg.setRGB(fakeX + i, y + j, avgMatrix(matrix));} else {// 這里把背景設為透明puzzleImg.setRGB(i, j, rgb_ori & 0x00ffffff);}}}}/*** 隨機獲取虛假x坐標的值** @param x 真正的x坐標* @return fakeX*/private static int getRandomFakeX(int x) {int puzzleRealWidth = puzzleWidth + 2 * borderSize + 2;Random random = new Random();int fakeX = random.nextInt(width - 2 * puzzleRealWidth) + puzzleRealWidth;if (Math.abs(fakeX - x) <= puzzleRealWidth) {fakeX = width - x;}return fakeX;}/*** 通過拼圖圖片生成登高拼圖圖片** @param puzzleImg 拼圖圖片* @param offsetY   隨機生成的y* @return 登高拼圖圖片*/private static BufferedImage reshapeAccordant(BufferedImage puzzleImg, int offsetY) {BufferedImage puzzleBlankImg = new BufferedImage(puzzleWidth + 2 * borderSize + 2, height, BufferedImage.TYPE_4BYTE_ABGR);Graphics2D graphicsPuzzle = puzzleBlankImg.createGraphics();graphicsPuzzle.drawImage(puzzleImg, 1, offsetY, null);graphicsPuzzle.dispose();return puzzleBlankImg;}private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {int xStart = x - 1;int yStart = y - 1;int current = 0;for (int i = xStart; i < 3 + xStart; i++) {for (int j = yStart; j < 3 + yStart; j++) {int tx = i;if (tx < 0) {tx = -tx;} else if (tx >= img.getWidth()) {tx = x;}int ty = j;if (ty < 0) {ty = -ty;} else if (ty >= img.getHeight()) {ty = y;}pixels[current++] = img.getRGB(tx, ty);}}}private static int avgMatrix(int[][] matrix) {int r = 0;int g = 0;int b = 0;for (int[] x : matrix) {for (int j = 0; j < x.length; j++) {if (j == 1) {continue;}Color c = new Color(x[j]);r += c.getRed();g += c.getGreen();b += c.getBlue();}}return new Color(r / 8, g / 8, b / 8).getRGB();}private static void fillMatrix(int[][] matrix, int[] values) {int filled = 0;for (int[] x : matrix) {for (int j = 0; j < x.length; j++) {x[j] = values[filled++];}}}
}

RandomUtil:

package com.xloda.common.tool.captcha.util;import com.xloda.common.tool.captcha.constant.CaptchaConstants;import java.util.Random;/*** @author Dragon Wu* @since 2025/04/23 18:07* 隨機生成器工具*/public class RandomUtil {// 隨機獲取背景圖路徑public static String randomBgImgPath() {int index = new Random().nextInt(CaptchaConstants.BG_IMAGES.length);return CaptchaConstants.BG_IMAGES[index];}
}

ImageUtil:

package com.xloda.common.tool.captcha.util;import com.xloda.common.tool.captcha.constant.CaptchaConstants;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;/*** @author Dragon Wu* @since 2025/04/25 10:18* 圖片處理工具*/public class ImageUtil {public static BufferedImage addBorderWithOutline(BufferedImage image, int borderWidth, Color borderColor) {// 創建新圖像,尺寸擴大以容納邊框BufferedImage result = new BufferedImage(image.getWidth() + borderWidth * 2,image.getHeight() + borderWidth * 2,BufferedImage.TYPE_INT_ARGB);Graphics2D g2d = result.createGraphics();g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 獲取圖像的非透明區域Area area = new Area();for (int y = 0; y < image.getHeight(); y++) {for (int x = 0; x < image.getWidth(); x++) {if ((image.getRGB(x, y) >> 24) != 0x00) {area.add(new Area(new Rectangle(x, y, 1, 1)));}}}// 繪制邊框g2d.setColor(borderColor);g2d.setStroke(new BasicStroke(borderWidth * 2));g2d.translate(borderWidth, borderWidth);g2d.draw(area);// 繪制原始圖像g2d.drawImage(image, 0, 0, null);g2d.dispose();return result;}// 圖片轉Base64public static String toBase64(BufferedImage image) throws IOException {// 創建一個字節數組輸出流ByteArrayOutputStream os = new ByteArrayOutputStream();// 將BufferedImage寫入到輸出流中,這里指定圖片格式為"png"或"jpg"等ImageIO.write(image, CaptchaConstants.IMG_FORMAT, os);// 將輸出流的字節數組轉換為Base64編碼的字符串String imageBase64 = Base64.getEncoder().encodeToString(os.toByteArray());// 關閉輸出流os.close();return CaptchaConstants.BASE64_PREFIX + imageBase64;}
}

SliderCaptcha:

package com.xloda.common.tool.captcha.pojo;import lombok.*;/*** @author Dragon Wu* @since 2025/04/23 10:49* 滑塊驗證碼*/
@AllArgsConstructor
@Getter
@ToString
public class SliderCaptcha {// 驗證碼背景圖private String bgImg;// 驗證碼滑塊private String puzzleImg;// 驗證碼正確的x位置(此值需自行存入緩存,用于驗證碼判斷)private int x;// 等高拼圖時,返回0(非登高拼圖,此值需自行存入緩存,用于驗證碼判斷)private int y;public SliderCaptcha(String bgImg, String puzzleImg, int x) {this.bgImg = bgImg;this.puzzleImg = puzzleImg;this.x = x;}
}

CaptchaConstants:

package com.xloda.common.tool.captcha.constant;/*** @author Dragon Wu* @since 2025/04/23 10:53*/
public interface CaptchaConstants {// 圖片格式String IMG_FORMAT = "png";// base64前綴String BASE64_PREFIX = "data:image/" + IMG_FORMAT + ";base64,";// 圖片存儲的目錄String FOLDER = "/static/img/captcha/";// 背景圖列表(引入依賴后,記得在項目資源目錄的該路徑下添加對應圖片)String[] BG_IMAGES = new String[]{FOLDER + "bg01.png",FOLDER + "bg01.png"};
}

SliderCaptchaConfig

package com.xloda.common.tool.captcha.constant;/*** @author Dragon Wu* @since 2025/04/23 11:09* 滑塊驗證碼的配置*/public interface SliderCaptchaConfig {// 大圖寬度(原圖裁剪拼圖后的背景圖)int width = 280;// 大圖高度int height = 173;// 小圖寬度(滑塊拼圖),前端拼圖的實際寬度:puzzleWidth + 2 * borderSize + 2int puzzleWidth = 66;// 小圖高度,前端拼圖的實際高度:puzzleHeight + 2 * borderSize + 2int puzzleHeight = 66;// 邊框厚度int borderSize = 1;// 小圓半徑,即拼圖上的凹凸輪廓半徑int radius = 8;// 圖片一周預留的距離,randomR1最大值不能超過radius * 3 / 2int distance = radius * 3 / 2;
}

接下來繼續手搓旋轉驗證碼前后端。

本節,總結到此,學點數學挺有用的!

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

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

相關文章

關于flink兩階段提交高并發下程序卡住問題

先拋出代碼 package com.dpf.flink;import com.dpf.flink.sink.MysqlSink; import org.apache.flink.api.common.serialization.SimpleStringSchema; import org.apache.flink.api.common.typeinfo.Types; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.…

html css js網頁制作成品——HTML+CSS+js美甲店網頁設計(5頁)附源碼

美甲店 目錄 一、&#x1f468;?&#x1f393;網站題目 二、??網站描述 三、&#x1f4da;網站介紹 四、&#x1f310;網站效果 五、&#x1fa93; 代碼實現 &#x1f9f1;HTML 六、&#x1f947; 如何讓學習不再盲目 七、&#x1f381;更多干貨 一、&#x1f468;?&a…

LeetCode[347]前K個高頻元素

思路&#xff1a; 使用小頂堆&#xff0c;最小的元素都出去了&#xff0c;省的就是大&#xff0c;高頻的元素了&#xff0c;所以要維護一個小頂堆&#xff0c;使用map存元素高頻變化&#xff0c;map存堆里&#xff0c;然后輸出堆的東西就行了 代碼&#xff1a; class Solution…

2024年網站開發語言選擇指南:PHP/Java/Node.js/Python如何選型?

2024年網站開發語言選擇指南&#xff1a;PHP/Java/Node.js/Python如何選型&#xff1f; 一、8大主流Web開發語言技術對比 1. PHP開發&#xff1a;中小型網站的首選方案 最新版本&#xff1a;PHP 8.3&#xff08;2023年11月發布&#xff09;核心優勢&#xff1a; 全球78%的網站…

從數據結構說起(一)

1 揭開數據結構神奇的面紗 1.1 初識數據結構 在C的標準庫模板&#xff08;Standard Template Library,STL&#xff09;課程上&#xff0c;我初次結識了《數據結構》。C語言提供的標準庫模板是面向對象程序設計與泛型程序設計思想相結合的典范。所謂的泛型編程就是編寫不依賴于具…

JAVA--- 關鍵字static

之前我們學習了JAVA 面向對象的一些基本知識&#xff0c;今天來進階一下&#xff01;&#xff01;&#xff01; static關鍵字 static表示靜態&#xff0c;是JAVA中的一個修飾符&#xff0c;可以修飾成員方法&#xff0c;成員變量&#xff0c;可用于修飾類的成員&#xff08;變…

4.27比賽總結

文章目錄 T1T2法一&#xff1a;倍增求 LCA法二&#xff1a;Dijkstra 求最短路法三&#xff1a;dfs 求深度 T3T4總結 T1 一道非常簡單的題&#xff0c;結果我因為一句話沒寫掛了 80pts…… 題目中沒寫 a a a 數組要按照 b b b 數組的順序&#xff0c;所以對于最大方案&#x…

數據一致性巡檢總結:基于分桶采樣的設計與實現

數據一致性巡檢總結&#xff1a;基于分桶采樣的設計與實現 背景 在分布式系統中&#xff0c;緩存&#xff08;如 Redis&#xff09;與數據庫&#xff08;如 MySQL&#xff09;之間的數據一致性問題是一個常見的挑戰。由于緩存的引入&#xff0c;數據在緩存和數據庫之間可能存…

SpringBoot與Druid整合,實現主從數據庫同步

通過引入主從數據庫同步系統&#xff0c;可以顯著提升平臺的性能和穩定性&#xff0c;同時保證數據的一致性和安全性。Druid連接池也提供了強大的監控和安全防護功能&#xff0c;使得整個系統更加健壯和可靠。 我們為什么選擇Druid&#xff1f; 高效的連接管理&#xff1a;Dru…

在Linux系統中安裝MySQL,二進制包版

1、檢查是否已安裝數據庫&#xff08;rpm軟件包管理器&#xff09; rpm -qa | grep mysql rpm -qa | grep mariadb #centOS7自帶mariadb與mysql數據庫沖突2、刪除已有數據庫 rpm -e –nodeps 軟件名稱 3、官網下載MySQL包 4、上傳 # 使用FinalShell或Xshell工具上傳&#…

【含文檔+PPT+源碼】基于SpringBoot電腦DIY裝機教程網站的設計與實現

項目介紹 本課程演示的是一款 基于SpringBoot電腦DIY裝機教程網站的設計與實現&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 1.包含&#xff1a;項目源碼、項目文檔、數據庫腳本、軟件工具等所有資料 2.帶你從零開始部署運行本套…

Spring Boot 緩存機制:從原理到實踐

文章目錄 一、引言二、Spring Boot 緩存機制原理2.1 緩存抽象層2.2 緩存注解2.3 緩存管理器 三、入門使用3.1 引入依賴3.2 配置緩存3.3 啟用緩存3.4 使用緩存注解3.5 實體類 四、踩坑記錄4.1 緩存鍵生成問題4.2 緩存過期與更新問題4.3 事務與緩存的一致性問題 五、心得體會5.1 …

Spark讀取Apollo配置

--conf spark.driver.extraJavaOptions-Dapp.idapollo的app.id -Denvfat -Dapollo.clusterfat -Dfat_metaapollo的meta地址 --conf spark.executor.extraJavaOptions-Dapp.idapollo的app.id -Denvfat -Dapollo.clusterfat -Dfat_metaapollo的meta地址 在spark的提交命令中&…

[逆向工程]如何理解小端序?逆向工程中的字節序陷阱與實戰解析

[逆向工程]如何理解小端序&#xff1f;逆向工程中的字節序陷阱與實戰解析 關鍵詞&#xff1a;逆向工程、小端序、字節序、二進制分析、數據解析 引言&#xff1a;為什么字節序是逆向工程師的必修課&#xff1f; 在逆向工程中&#xff0c;分析二進制數據是最基礎的任務之一。…

項目三 - 任務2:創建筆記本電腦類(一爹多叔)

在本次實戰中&#xff0c;我們通過Java的單根繼承和多接口實現特性&#xff0c;設計了一個筆記本電腦類。首先創建了Computer抽象類&#xff0c;提供計算的抽象方法&#xff0c;模擬電腦的基本功能。接著定義了NetCard和USB兩個接口&#xff0c;分別包含連接網絡和USB設備的抽象…

ElasticSearch深入解析(六):集群核心配置

1.開發模式和生產模式 Elasticsearch默認運行在開發模式下&#xff0c;此模式允許節點在配置存在錯誤時照常啟動&#xff0c;僅將警告信息寫入日志文件。而生產模式則更為嚴格&#xff0c;一旦檢測到配置錯誤&#xff0c;節點將無法啟動&#xff0c;這是一種保障系統穩定性的安…

【Prometheus-MySQL Exporter安裝配置指南,開機自啟】

目錄 1. 創建 MySQL 監控用戶2. 配置 MySQL 認證文件3. 安裝 mysqld_exporter4. 配置 Systemd 服務5. 啟動并驗證服務6. 修改Prometheus配置常見錯誤排查錯誤現象排查步驟 6. 驗證監控數據關鍵注意事項 7. Grafana看板 1. 創建 MySQL 監控用戶 mysql -uroot -p123456 # 登錄M…

redis未授權訪問漏洞學習

一、Redis常見用途 1. Redis介紹 全稱與起源: Redis全稱Remote Dictionary Service(遠程字典服務)&#xff0c;最初由antirez在2009年開發&#xff0c;用于解決網站訪問記錄統計的性能問題。發展歷程: 從最初僅支持列表功能的內存數據庫&#xff0c;經過十余年發展已支持多種…

4.27搭建用戶界面

更新 router下面的index.js添加新的children 先區分一下views文件夾下的不同vue文件&#xff1a; Home.vue是繪制home頁面的所有的表格。 Main.vue是架構頭部和左側目錄的框架的。 研究一下這個routes對象&#xff0c;就可以發現重定向redirect的奧妙所在&#xff0c;我們先把…

【MySQL】(8) 聯合查詢

一、聯合查詢的作用 由于范式的規則&#xff0c;數據分到多個表中&#xff0c;想要查詢完整的信息&#xff0c;就需要聯合查詢多張表。比如查詢學生的學生信息和所在班級的信息&#xff0c;就需要聯合查詢學生表和班級表。 二、聯合查詢過程 案例&#xff1a;查詢學生姓名為孫…