Java實(shí)現(xiàn)SSL Socket長(zhǎng)連接方式
一、單向認(rèn)證
1、生成服務(wù)端密鑰(配置了jdk的環(huán)境變量即可用keytool命令)
命令:keytool -genkey -keystore server_ks.jks -storepass server_password -keyalg RSA -keypass server_password
結(jié)果:會(huì)生成server_ks.jks密鑰文件
操作:將生成的server_ks.jks密鑰文件配置到服務(wù)端

2、生成服務(wù)端證書(shū)
命令:keytool -export -keystore server_ks.jks -storepass server_password -file server.cer
結(jié)果:會(huì)生成server.cer證書(shū)文件
操作:將生成的server.cer證書(shū)文件配置到客戶(hù)端

3、服務(wù)端代碼
package com.ssl.server;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
public class ServerTest {
public static File writeToFile1 = new File("C:\\Users\\Li\\Desktop\\temp\\配置.txt");
public static File writeToFile2 = new File("C:\\Users\\Li\\Desktop\\temp\\配置2.txt");
public static void main(String[] args) {
new Thread(new ServerOne()).start();
}
public static class ServerOne implements Runnable {
//SSL協(xié)議版本
private static final String TLS = "TLSv1.2";
//KeyStore的類(lèi)型
private static final String PROVIDER = "SunX509";
//秘鑰類(lèi)型,java默認(rèn)是JKS
private static final String STORE_TYPE = "JKS";
//秘鑰的路徑
private static final String KEY_STORE_NAME = "E:\\02-IDEA_Project\\Test02_HttpsServer\\server_ks.jks";
//Server的端口
private static final int DEFAULT_PORT = 8090; //自定義端口
//秘鑰的密碼
private static final String SERVER_KEY_STORE_PASSWORD = "server_password";
@Override
public void run() {
SSLServerSocket sslServerSocket = null;
try {
//獲取SSLContext
SSLContext sslContext = SSLContext.getInstance(TLS);
//生成秘鑰的manager
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(PROVIDER);
//加載秘鑰
KeyStore keyStoreOne = KeyStore.getInstance(STORE_TYPE);
keyStoreOne.load(new FileInputStream(KEY_STORE_NAME), SERVER_KEY_STORE_PASSWORD.toCharArray());
//秘鑰初始化
keyManagerFactory.init(keyStoreOne, SERVER_KEY_STORE_PASSWORD.toCharArray());
//初始化SSLContext
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
//獲取SSLContext的SocketFactory
sslServerSocket = (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket(DEFAULT_PORT);
//是否開(kāi)啟雙向驗(yàn)證
sslServerSocket.setNeedClientAuth(false);
System.out.println("服務(wù)器已開(kāi)啟,等待連接 .....");
while (true) {
Socket accept = sslServerSocket.accept();
accept.setKeepAlive(true);
System.out.println("客戶(hù)端 : " + accept.getInetAddress().getHostAddress());
try (
InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();
) {
byteMsgReader(inputStream, outputStream);
// socket.shutdownOutput(); // 長(zhǎng)連接則不關(guān)閉輸出流
// socket.shutdownInput(); // 長(zhǎng)連接則不關(guān)閉輸入流
} catch (Exception e) {
System.out.println(e.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
try {
if (sslServerSocket != null) {
sslServerSocket.close();
System.out.println("服務(wù)器關(guān)閉!");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
/**
* 字節(jié)流-解析客戶(hù)端的消息
*/
public static void byteMsgReader(InputStream inputStream, OutputStream outputStream) throws Exception {
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
FileOutputStream bufferedOutputStream1 = new FileOutputStream(writeToFile1, false);
FileOutputStream bufferedOutputStream2 = new FileOutputStream(writeToFile2, false);
byte[] b = new byte[4096];
int i = 0;
while ((i = bufferedInputStream.read(b)) > 0) {
bufferedOutputStream1.write(b, 0, i);
bufferedOutputStream1.flush();
if (i < b.length) { // 根據(jù)讀取的長(zhǎng)度是否滿(mǎn)格判斷當(dāng)前文件是否已讀取完畢
bufferedOutputStream1.close();
break;
}
}
System.out.println("接收完成第一個(gè)文件");
byteMsgWriter(outputStream);
i = 0;
byte[] b2 = new byte[4096];
while ((i = bufferedInputStream.read(b2)) > 0) {
bufferedOutputStream2.write(b2, 0, i);
bufferedOutputStream2.flush();
if (i < b2.length) { // 根據(jù)讀取的長(zhǎng)度是否滿(mǎn)格判斷當(dāng)前文件是否已讀取完畢
bufferedOutputStream2.close();
break;
}
}
System.out.println("接收完成第二個(gè)文件");
byteMsgWriter(outputStream);
}
/**
* 字節(jié)流-發(fā)送給客戶(hù)端回執(zhí)消息
*/
public static void byteMsgWriter(OutputStream outputStream) throws Exception {
BufferedOutputStream bufferedOutputStreamBack = new BufferedOutputStream(outputStream);
bufferedOutputStreamBack.write("服務(wù)端已成功接收文件.".getBytes(StandardCharsets.UTF_8));
bufferedOutputStreamBack.write("\n".getBytes(StandardCharsets.UTF_8));
bufferedOutputStreamBack.flush(); // 第一次發(fā)送消息,長(zhǎng)連接實(shí)現(xiàn)方式
}
}4、客戶(hù)端代碼
package com.ssl.client;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
public class ClientTest {
public static File readFile = new File("C:\\Users\\Li\\Desktop\\temp\\sqlV2.0.sql");
public static void main(String[] args) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new ClientOne()).start();
}
public static class ClientOne implements Runnable {
private static final String TLS = "TLSv1.2";
private static final String PROVIDER = "SunX509";
private static final String STORE_TYPE = "JKS";
private static final String TRUST_STORE_NAME = "E:\\02-IDEA_Project\\Test01_HttpsClient\\server.cer";
@Override
public void run() {
SSLSocket socket = null;
try {
SSLContext sslContext = SSLContext.getInstance(TLS);
//生成信任證書(shū)Manager,默認(rèn)系統(tǒng)會(huì)信任CA機(jī)構(gòu)頒發(fā)的證書(shū),自定的證書(shū)需要手動(dòng)的加載
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(PROVIDER);
KeyStore keyStore = KeyStore.getInstance(STORE_TYPE);
keyStore.load(null);
//生成驗(yàn)證工廠(chǎng)
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
//生成別名(可以隨便填寫(xiě))
String certificateAlias = Integer.toString(0);
//加載證書(shū)
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(new FileInputStream(TRUST_STORE_NAME)));
//初始化
trustManagerFactory.init(keyStore);
//初始化
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
socket = (SSLSocket) sslContext.getSocketFactory().createSocket("localhost", 8090);
socket.setKeepAlive(true);
// socket.setSoTimeout(10000); //設(shè)置超時(shí)時(shí)間
try (
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
) {
byteMsgWriter(outputStream, inputStream);
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
try {
if (socket != null) {
socket.close();
System.out.println("客戶(hù)端關(guān)閉");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
/**
* 字節(jié)流-發(fā)送給服務(wù)端
*/
public static void byteMsgWriter(OutputStream outputStream, InputStream inputStream) throws Exception {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(readFile));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
//mark后讀取超過(guò)readlimit字節(jié)數(shù)據(jù),mark標(biāo)記就會(huì)失效
bufferedInputStream.mark(909600000);
byte[] b = new byte[4096];
int i;
while ((i = bufferedInputStream.read(b)) > 0) {
bufferedOutputStream.write(b, 0, i);
bufferedOutputStream.flush(); // 第一次發(fā)送消息,長(zhǎng)連接實(shí)現(xiàn)方式
}
bufferedInputStream.reset();
Thread.sleep(1); // 必須加休眠,否則第二個(gè)文件流會(huì)發(fā)生錯(cuò)亂
characterMsgReader(inputStream); // 從服務(wù)端接收消息
while ((i = bufferedInputStream.read(b)) > 0) {
bufferedOutputStream.write(b, 0, i);
bufferedOutputStream.flush(); // 第二次發(fā)送消息,長(zhǎng)連接實(shí)現(xiàn)方式
}
characterMsgReader(inputStream); // 從服務(wù)端接收消息
}
/**
* 字符流-解析服務(wù)端的回執(zhí)消息-不間斷解析
*/
public static void characterMsgReader(InputStream inputStream) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println("服務(wù)端消息: " + line);
}
}
}二、雙向認(rèn)證
1、生成客戶(hù)端密鑰
命令:keytool -genkey -keystore client_ks.jks -storepass client_password -keyalg RSA -keypass client_password
結(jié)果:會(huì)生成client_ks.jks密鑰文件
操作:將生成的client_ks.jks密鑰文件配置到客戶(hù)端

2、生成客戶(hù)端證書(shū)
命令:keytool -export -keystore client_ks.jks -storepass client_password -file client.cer
結(jié)果:會(huì)生成client.cer證書(shū)文件

3、將server端證書(shū)添加到serverTrust_ks.jks文件中
命令:keytool -import -keystore serverTrust_ks.jks -storepass client -file server.cer
結(jié)果:會(huì)生成serverTrust_ks.jks密鑰文件
操作:將生成的serverTrust_ks.jks密鑰文件配置到客戶(hù)端

4、將client端證書(shū)添加到clientTrust_ks.jks文件中
命令:keytool -import -keystore clientTrust_ks.jks -storepass server -file client.cer
結(jié)果:會(huì)生成clientTrust_ks.jks密鑰文件
操作:將生成的clientTrust_ks.jks密鑰文件配置到服務(wù)端

5、服務(wù)端代碼
package com.ssl.server;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
public class Server {
public static File writeToFile1 = new File("C:\\Users\\Li\\Desktop\\temp\\配置.txt");
public static File writeToFile2 = new File("C:\\Users\\Li\\Desktop\\temp\\配置2.txt");
public static void main(String[] args) {
new Thread(new ServerOne()).start();
}
public static class ServerOne implements Runnable {
//SSL協(xié)議版本
private static final String TLS = "TLSv1.2";
//KeyStore的類(lèi)型
private static final String PROVIDER = "SunX509";
//秘鑰類(lèi)型,java默認(rèn)是JKS,Android不支持JKS,只能用BKS
private static final String STORE_TYPE = "JKS";
//秘鑰的路徑
private static final String KEY_STORE_NAME = "E:\\02-IDEA_Project\\Test02_HttpsServer\\server_ks.jks";
private static final String TRUST_STORE_NAME = "E:\\02-IDEA_Project\\Test02_HttpsServer\\clientTrust_ks.jks";
//Server的端口
private static final int DEFAULT_PORT = 8090; //自定義端口
//秘鑰的密碼
private static final String SERVER_KEY_STORE_PASSWORD = "server_password"; //秘鑰的密碼
private static final String SERVER_TRUST_KEY_STORE_PASSWORD = "server";//密碼
@Override
public void run() {
SSLServerSocket sslServerSocket = null;
try {
//獲取SSLContext
SSLContext sslContext = SSLContext.getInstance(TLS);
//生成秘鑰的manager
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(PROVIDER);
//加載信任的證書(shū)
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(PROVIDER);
//加載秘鑰
KeyStore keyStoreOne = KeyStore.getInstance(STORE_TYPE);
KeyStore keyStoreTwo = KeyStore.getInstance(STORE_TYPE);
keyStoreOne.load(new FileInputStream(KEY_STORE_NAME), SERVER_KEY_STORE_PASSWORD.toCharArray());
keyStoreTwo.load(new FileInputStream(TRUST_STORE_NAME), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());
//秘鑰初始化
keyManagerFactory.init(keyStoreOne, SERVER_KEY_STORE_PASSWORD.toCharArray());
trustManagerFactory.init(keyStoreTwo);
//初始化SSLContext
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
//獲取SSLContext的SocketFactory
sslServerSocket = (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket(DEFAULT_PORT);
//是否開(kāi)啟雙向驗(yàn)證
sslServerSocket.setNeedClientAuth(true);
System.out.println("服務(wù)器已開(kāi)啟,等待連接 .....");
while (true) {
Socket accept = sslServerSocket.accept();
accept.setKeepAlive(true);
System.out.println("客戶(hù)端 : " + accept.getInetAddress().getHostAddress());
try (
InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();
) {
byteMsgReader(inputStream, outputStream);
// socket.shutdownOutput(); // 長(zhǎng)連接則不關(guān)閉輸出流
// socket.shutdownInput(); // 長(zhǎng)連接則不關(guān)閉輸入流
} catch (Exception e) {
System.out.println(e.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
try {
if (sslServerSocket != null) {
sslServerSocket.close();
System.out.println("服務(wù)器關(guān)閉!");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
/**
* 字節(jié)流-解析客戶(hù)端的消息
*/
public static void byteMsgReader(InputStream inputStream, OutputStream outputStream) throws Exception {
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
FileOutputStream bufferedOutputStream1 = new FileOutputStream(writeToFile1, false);
FileOutputStream bufferedOutputStream2 = new FileOutputStream(writeToFile2, false);
byte[] b = new byte[4096];
int i = 0;
while ((i = bufferedInputStream.read(b)) > 0) {
bufferedOutputStream1.write(b, 0, i);
bufferedOutputStream1.flush();
if (i < b.length) { // 根據(jù)讀取的長(zhǎng)度是否滿(mǎn)格判斷當(dāng)前文件是否已讀取完畢
bufferedOutputStream1.close();
break;
}
}
System.out.println("接收完成第一個(gè)文件");
byteMsgWriter(outputStream);
i = 0;
byte[] b2 = new byte[4096];
while ((i = bufferedInputStream.read(b2)) > 0) {
bufferedOutputStream2.write(b2, 0, i);
bufferedOutputStream2.flush();
if (i < b2.length) { // 根據(jù)讀取的長(zhǎng)度是否滿(mǎn)格判斷當(dāng)前文件是否已讀取完畢
bufferedOutputStream2.close();
break;
}
}
System.out.println("接收完成第二個(gè)文件");
byteMsgWriter(outputStream);
}
/**
* 字節(jié)流-發(fā)送給客戶(hù)端回執(zhí)消息
*/
public static void byteMsgWriter(OutputStream outputStream) throws Exception {
BufferedOutputStream bufferedOutputStreamBack = new BufferedOutputStream(outputStream);
bufferedOutputStreamBack.write("服務(wù)端已成功接收文件.".getBytes(StandardCharsets.UTF_8));
bufferedOutputStreamBack.write("\n".getBytes(StandardCharsets.UTF_8));
bufferedOutputStreamBack.flush(); // 第一次發(fā)送消息,長(zhǎng)連接實(shí)現(xiàn)方式
}
}6、客戶(hù)端代碼
package com.ssl.client;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.security.KeyStore;
public class Client {
public static File readFile = new File("C:\\Users\\Li\\Desktop\\temp\\sqlV2.0.sql");
public static void main(String[] args) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new ClientOne()).start();
}
public static class ClientOne implements Runnable {
private static final String TLS = "TLSv1.2";
private static final String PROVIDER = "SunX509";
private static final String STORE_TYPE = "JKS";
private static final String TRUST_STORE_NAME = "E:\\02-IDEA_Project\\Test01_HttpsClient\\serverTrust_ks.jks";
private static final String KEY_STORE_NAME = "E:\\02-IDEA_Project\\Test01_HttpsClient\\client_ks.jks";
private static final String CLIENT_KEY_STORE_PASSWORD = "client_password"; //密碼
private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "client";//密碼
@Override
public void run() {
SSLSocket socket = null;
try {
SSLContext sslContext = SSLContext.getInstance(TLS);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(PROVIDER);
//生成信任證書(shū)Manager,默認(rèn)系統(tǒng)會(huì)信任CA機(jī)構(gòu)頒發(fā)的證書(shū),自定的證書(shū)需要手動(dòng)的加載
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(PROVIDER);
KeyStore keyStoreOne = KeyStore.getInstance(STORE_TYPE);
KeyStore keyStoreTwo = KeyStore.getInstance(STORE_TYPE);
//加載client端密鑰
keyStoreOne.load(new FileInputStream(KEY_STORE_NAME), CLIENT_KEY_STORE_PASSWORD.toCharArray());
//信任證書(shū)
keyStoreTwo.load(new FileInputStream(TRUST_STORE_NAME), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
keyManagerFactory.init(keyStoreOne, CLIENT_KEY_STORE_PASSWORD.toCharArray());
trustManagerFactory.init(keyStoreTwo);
//初始化
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
//此種寫(xiě)法代表客戶(hù)端信任所有證書(shū)
/*TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
}};
//初始化
sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCerts, null);*/
socket = (SSLSocket) sslContext.getSocketFactory().createSocket("localhost", 8090);
socket.setKeepAlive(true);
// socket.setSoTimeout(10000);
try (
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
) {
byteMsgWriter(outputStream, inputStream);
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
try {
if (socket != null) {
socket.close();
System.out.println("客戶(hù)端關(guān)閉");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
/**
* 字節(jié)流-發(fā)送給服務(wù)端
*/
public static void byteMsgWriter(OutputStream outputStream, InputStream inputStream) throws Exception {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(readFile));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
//mark后讀取超過(guò)readlimit字節(jié)數(shù)據(jù),mark標(biāo)記就會(huì)失效
bufferedInputStream.mark(909600000);
byte[] b = new byte[4096];
int i;
while ((i = bufferedInputStream.read(b)) > 0) {
bufferedOutputStream.write(b, 0, i);
bufferedOutputStream.flush(); // 第一次發(fā)送消息,長(zhǎng)連接實(shí)現(xiàn)方式
}
bufferedInputStream.reset();
Thread.sleep(1); // 必須加休眠,否則第二個(gè)文件流會(huì)發(fā)生錯(cuò)亂
characterMsgReader(inputStream); // 從服務(wù)端接收消息
while ((i = bufferedInputStream.read(b)) > 0) {
bufferedOutputStream.write(b, 0, i);
bufferedOutputStream.flush(); // 第二次發(fā)送消息,長(zhǎng)連接實(shí)現(xiàn)方式
}
characterMsgReader(inputStream); // 從服務(wù)端接收消息
}
/**
* 字符流-解析服務(wù)端的回執(zhí)消息-不間斷解析
*/
public static void characterMsgReader(InputStream inputStream) throws Exception {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println("服務(wù)端消息: " + line);
}
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot結(jié)合Maven項(xiàng)目依賴(lài)版本沖突問(wèn)題解決
本文主要介紹了SpringBoot結(jié)合Maven項(xiàng)目依賴(lài)版本沖突問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
解決SSLContext.getInstance()中參數(shù)設(shè)置TLS版本無(wú)效的問(wèn)題
這篇文章主要介紹了解決SSLContext.getInstance()中參數(shù)設(shè)置TLS版本無(wú)效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
華為鴻蒙系統(tǒng)應(yīng)用開(kāi)發(fā)工具 DevEco Studio的安裝和使用圖文教程
HUAWEI DevEco Studio 是華為消費(fèi)者業(yè)務(wù)為開(kāi)發(fā)者提供的集成開(kāi)發(fā)環(huán)境(IDE),旨在幫助開(kāi)發(fā)者快捷、方便、高效地使用華為EMUI開(kāi)放能力。這篇文章主要介紹了華為鴻蒙系統(tǒng)應(yīng)用開(kāi)發(fā)工具 DevEco Studio的安裝和使用圖文教程,需要的朋友可以參考下2021-04-04
SpringBoot實(shí)現(xiàn)接口防刷的五種方案
接口防刷是保障系統(tǒng)安全與穩(wěn)定性的重要措施,惡意的高頻請(qǐng)求不僅會(huì)消耗服務(wù)器資源,還可能導(dǎo)致數(shù)據(jù)異常,甚至系統(tǒng)癱瘓,本文將介紹在SpringBoot框架下實(shí)現(xiàn)接口防刷的5種技術(shù)方案,需要的朋友可以參考下2025-04-04
靈活控制任務(wù)執(zhí)行時(shí)間的Cron表達(dá)式范例
這篇文章主要為大家介紹了靈活控制任務(wù)執(zhí)行時(shí)間的Cron表達(dá)式范例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
一篇超詳細(xì)的Spring Boot整合Mybatis文章
大家都知道springboot搭建一個(gè)spring框架只需要秒秒鐘。下面通過(guò)實(shí)例代碼給大家介紹一下springboot與mybatis的完美融合,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2021-07-07
Java實(shí)現(xiàn)PDF轉(zhuǎn)HTML/Word/Excel/PPT/PNG的示例代碼
這篇文章主要為大家介紹了如何利用Java語(yǔ)言是PDF轉(zhuǎn)HTML、Word、Excel、PPT和PNG功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-05-05

