Spring Boot中WebSocket常用使用方法詳解
在實(shí)時(shí)性要求較高的應(yīng)用場景,如在線聊天、實(shí)時(shí)數(shù)據(jù)監(jiān)控、股票行情推送等,傳統(tǒng)的HTTP協(xié)議由于其請求-響應(yīng)的模式,無法高效實(shí)現(xiàn)服務(wù)器與客戶端之間的雙向?qū)崟r(shí)通信。而WebSocket協(xié)議的出現(xiàn)解決了這一難題,它允許在單個(gè)TCP連接上進(jìn)行全雙工通信,使得服務(wù)器和客戶端可以隨時(shí)主動(dòng)發(fā)送消息。Spring Boot對WebSocket提供了良好的支持,極大地簡化了開發(fā)流程。本文將從入門到精通,詳細(xì)介紹Spring Boot中WebSocket的常用使用方法。
一、WebSocket基礎(chǔ)概念
1.1 什么是WebSocket
WebSocket是一種網(wǎng)絡(luò)通信協(xié)議,于2011年被IETF定為標(biāo)準(zhǔn)RFC 6455,并被HTML5所支持 。與HTTP協(xié)議不同,WebSocket在建立連接后,通信雙方可以隨時(shí)主動(dòng)發(fā)送和接收數(shù)據(jù),無需像HTTP那樣每次通信都要建立新的連接,從而減少了開銷,提高了實(shí)時(shí)性。
1.2 WebSocket與HTTP的區(qū)別
特性 | HTTP | WebSocket |
---|---|---|
通信模式 | 客戶端發(fā)起請求,服務(wù)器響應(yīng)(單向) | 全雙工通信(雙向) |
連接方式 | 每次請求都需建立新連接 | 一次握手建立持久連接 |
數(shù)據(jù)格式 | 通常為文本(JSON、XML等) | 支持文本和二進(jìn)制數(shù)據(jù) |
應(yīng)用場景 | 適用于一般的Web頁面請求 | 適用于實(shí)時(shí)性要求高的場景 |
二、Spring Boot集成WebSocket
2.1 添加依賴
在Spring Boot項(xiàng)目的pom.xml
文件中添加WebSocket依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
如果使用Gradle,在build.gradle
中添加:
implementation 'org.springframework.boot:spring-boot-starter-websocket'
2.2 配置WebSocket
創(chuàng)建一個(gè)配置類,用于注冊WebSocket處理程序和配置消息代理:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(StompBrokerRelayRegistration config) { config.setApplicationDestinationPrefixes("/app"); config.setDestinationPrefixes("/topic"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket-endpoint").withSockJS(); } @Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); container.setMaxTextMessageBufferSize(65536); container.setMaxBinaryMessageBufferSize(65536); return container; } }
在上述代碼中:
@EnableWebSocketMessageBroker
注解啟用WebSocket消息代理。configureMessageBroker
方法配置消息代理的前綴,/app
用于應(yīng)用程序發(fā)送消息的目的地前綴,/topic
用于服務(wù)器發(fā)送消息的目的地前綴。registerStompEndpoints
方法注冊WebSocket端點(diǎn),addEndpoint
方法指定端點(diǎn)的路徑,withSockJS
表示啟用SockJS支持,以提供對不支持WebSocket瀏覽器的兼容。createWebSocketContainer
方法配置WebSocket容器的參數(shù),如消息緩沖區(qū)大小。
三、WebSocket常用使用方法
3.1 簡單消息收發(fā)
3.1.1 創(chuàng)建消息實(shí)體類
public class ChatMessage { private String sender; private String content; private MessageType type; // 省略構(gòu)造函數(shù)、Getter和Setter方法 public enum MessageType { CHAT, JOIN, LEAVE } }
ChatMessage
類用于封裝聊天消息,包含發(fā)送者、消息內(nèi)容和消息類型(聊天、加入、離開)。
3.1.2 創(chuàng)建消息處理類
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Controller; @Controller public class ChatController { @MessageMapping("/chat.send") @SendTo("/topic/public") public ChatMessage sendMessage(ChatMessage chatMessage) { return chatMessage; } @MessageMapping("/chat.join") @SendTo("/topic/public") public ChatMessage joinChat(ChatMessage chatMessage) { chatMessage.setType(ChatMessage.MessageType.JOIN); return chatMessage; } }
在上述代碼中:
@MessageMapping
注解用于映射客戶端發(fā)送的消息路徑,如"/chat.send"
和"/chat.join"
。@SendTo
注解指定消息發(fā)送的目的地,這里將消息發(fā)送到"/topic/public"
,所有訂閱該主題的客戶端都能接收到消息。sendMessage
方法處理聊天消息的發(fā)送,joinChat
方法處理用戶加入聊天的消息。
3.1.3 前端頁面實(shí)現(xiàn)
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>WebSocket Chat</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.1/sockjs.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/stompjs/2.3.3/stomp.min.js"></script> </head> <body> <input type="text" id="username" placeholder="用戶名"> <button onclick="connect()">連接</button> <div id="chat-window"></div> <input type="text" id="message" placeholder="輸入消息"> <button onclick="sendMessage()">發(fā)送</button> <script> let socket = new SockJS('/websocket-endpoint'); let stompClient = Stomp.over(socket); function connect() { let username = document.getElementById('username').value; stompClient.connect({}, function (frame) { console.log('Connected: ' + frame); stompClient.subscribe('/topic/public', function (message) { let chatWindow = document.getElementById('chat-window'); let msg = JSON.parse(message.body); if (msg.type === 'JOIN') { chatWindow.innerHTML += msg.sender + " 加入了聊天 "; } else { chatWindow.innerHTML += msg.sender + ": " + msg.content + " "; } }); let joinMessage = { sender: username, content: '', type: 'JOIN' }; stompClient.send("/app/chat.join", {}, JSON.stringify(joinMessage)); }); } function sendMessage() { let message = document.getElementById('message').value; let username = document.getElementById('username').value; let chatMessage = { sender: username, content: message, type: 'CHAT' }; stompClient.send("/app/chat.send", {}, JSON.stringify(chatMessage)); } </script> </body> </html>
前端頁面通過SockJS和StompJS庫與后端建立WebSocket連接,實(shí)現(xiàn)消息的發(fā)送和接收。
3.2 點(diǎn)對點(diǎn)消息發(fā)送
有時(shí)候需要實(shí)現(xiàn)一對一的消息發(fā)送,而不是廣播給所有客戶端??梢酝ㄟ^在@SendTo
中指定具體的用戶目的地來實(shí)現(xiàn)。
3.2.1 配置用戶目的地前綴
在WebSocketConfig
類中添加用戶目的地前綴配置:
@Override public void configureMessageBroker(StompBrokerRelayRegistration config) { config.setApplicationDestinationPrefixes("/app"); config.setDestinationPrefixes("/topic", "/user"); config.setUserDestinationPrefix("/user"); }
這里添加了/user
作為用戶目的地前綴。
3.2.2 修改消息處理類
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.springframework.stereotype.Controller; @Controller public class PrivateChatController { @MessageMapping("/chat.private") public void sendPrivateMessage(SimpMessageHeaderAccessor headerAccessor, ChatMessage chatMessage) { String recipient = chatMessage.getRecipient(); headerAccessor.getSessionAttributes().put("username", chatMessage.getSender()); this.stompMessagingTemplate.convertAndSendToUser(recipient, "/private", chatMessage); } }
在上述代碼中:
@MessageMapping("/chat.private")
映射處理點(diǎn)對點(diǎn)消息的路徑。SimpMessageHeaderAccessor
用于獲取和設(shè)置消息頭信息。stompMessagingTemplate.convertAndSendToUser
方法將消息發(fā)送到指定用戶的私有目的地。
3.2.3 前端實(shí)現(xiàn)點(diǎn)對點(diǎn)消息發(fā)送
function sendPrivateMessage() { let message = document.getElementById('message').value; let username = document.getElementById('username').value; let recipient = document.getElementById('recipient').value; let chatMessage = { sender: username, recipient: recipient, content: message, type: 'CHAT' }; stompClient.send("/app/chat.private", {}, JSON.stringify(chatMessage)); }
前端添加輸入接收者的文本框,并在發(fā)送消息時(shí)指定接收者,實(shí)現(xiàn)點(diǎn)對點(diǎn)消息發(fā)送。
3.3 消息攔截與認(rèn)證
在實(shí)際應(yīng)用中,可能需要對WebSocket消息進(jìn)行攔截和認(rèn)證,確保只有合法用戶才能進(jìn)行通信。
3.3.1 創(chuàng)建消息攔截器
import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.simp.stomp.StompCommand; import org.springframework.messaging.simp.stomp.StompHeaderAccessor; import org.springframework.messaging.support.ChannelInterceptor; import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.stereotype.Component; @Component public class WebSocketInterceptor implements ChannelInterceptor { @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); if (StompCommand.CONNECT.equals(accessor.getCommand())) { // 在這里進(jìn)行認(rèn)證邏輯,如檢查Token等 String token = accessor.getFirstNativeHeader("Authorization"); if (token == null ||!isValidToken(token)) { throw new RuntimeException("認(rèn)證失敗"); } } return message; } private boolean isValidToken(String token) { // 實(shí)現(xiàn)具體的Token驗(yàn)證邏輯 return true; } }
上述代碼創(chuàng)建了一個(gè)WebSocketInterceptor
攔截器,在preSend
方法中對連接請求進(jìn)行認(rèn)證,檢查請求頭中的Authorization
Token是否有效。
3.3.2 注冊攔截器
在WebSocketConfig
類中注冊攔截器:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(new WebSocketInterceptor()); } // 其他配置方法... }
通過configureClientInboundChannel
方法將攔截器注冊到客戶端入站通道,對所有進(jìn)入的消息進(jìn)行攔截處理。
四、不使用接口,基于注解的WebSocket實(shí)現(xiàn)
4.1 實(shí)現(xiàn)思路
在Spring Boot中,除了通過實(shí)現(xiàn)接口的方式處理WebSocket消息,還可以利用注解來簡化開發(fā)過程。通過@ServerEndpoint
注解定義WebSocket端點(diǎn),結(jié)合@OnOpen
、@OnMessage
、@OnClose
、@OnError
等注解,能夠輕松實(shí)現(xiàn)對WebSocket連接生命周期的監(jiān)聽,以及接收和處理客戶端發(fā)送的數(shù)據(jù)。
4.2 核心代碼實(shí)現(xiàn)
首先,創(chuàng)建一個(gè)WebSocket處理類:
import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; @ServerEndpoint("/ws/{userId}") public class MyWebSocket { // 靜態(tài)變量,用來記錄當(dāng)前在線連接數(shù)。應(yīng)該把它設(shè)計(jì)成線程安全的。 private static int onlineCount = 0; // concurrent包的線程安全Set,用來存放每個(gè)客戶端對應(yīng)的MyWebSocket對象。 private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<>(); // 與某個(gè)客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù) private Session session; // 接收userId private String userId; /** * 連接建立成功調(diào)用的方法 */ @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { this.session = session; this.userId = userId; webSocketSet.add(this); addOnlineCount(); System.out.println("有新連接加入!當(dāng)前在線人數(shù)為" + getOnlineCount()); } /** * 連接關(guān)閉調(diào)用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); subOnlineCount(); System.out.println("有一連接關(guān)閉!當(dāng)前在線人數(shù)為" + getOnlineCount()); } /** * 收到客戶端消息后調(diào)用的方法 * * @param message 客戶端發(fā)送過來的消息 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("來自客戶端" + userId + "的消息:" + message); // 群發(fā)消息 for (MyWebSocket item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } } /** * 發(fā)生錯(cuò)誤時(shí)調(diào)用 * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { System.out.println("發(fā)生錯(cuò)誤"); error.printStackTrace(); } public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { MyWebSocket.onlineCount++; } public static synchronized void subOnlineCount() { MyWebSocket.onlineCount--; } }
在上述代碼中:
@ServerEndpoint("/ws/{userId}")
注解定義了WebSocket的訪問端點(diǎn),{userId}
為路徑參數(shù),用于標(biāo)識不同的客戶端。@OnOpen
注解的方法在連接建立時(shí)被調(diào)用,用于初始化連接相關(guān)信息,并將當(dāng)前連接對象添加到在線連接集合中。@OnMessage
注解的方法在接收到客戶端發(fā)送的消息時(shí)被調(diào)用,實(shí)現(xiàn)了消息的接收和群發(fā)功能。@OnClose
注解的方法在連接關(guān)閉時(shí)被調(diào)用,從在線連接集合中移除當(dāng)前連接對象。@OnError
注解的方法在發(fā)生錯(cuò)誤時(shí)被調(diào)用,用于處理異常情況。
4.3 前端頁面適配
前端頁面同樣需要進(jìn)行相應(yīng)的修改,以連接基于注解實(shí)現(xiàn)的WebSocket端點(diǎn):
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>基于注解的WebSocket Chat</title> </head> <body> <input type="text" id="userId" placeholder="用戶ID"> <button onclick="connect()">連接</button> <div id="chat-window"></div> <input type="text" id="message" placeholder="輸入消息"> <button onclick="sendMessage()">發(fā)送</button> <script> let socket; function connect() { let userId = document.getElementById('userId').value; socket = new WebSocket("ws://localhost:8080/ws/" + userId); socket.onopen = function (event) { console.log("連接成功"); }; socket.onmessage = function (event) { let chatWindow = document.getElementById('chat-window'); chatWindow.innerHTML += "收到消息: " + event.data + " "; }; socket.onclose = function (event) { console.log("連接關(guān)閉"); }; socket.onerror = function (event) { console.log("連接錯(cuò)誤"); }; } function sendMessage() { let message = document.getElementById('message').value; if (socket && socket.readyState === WebSocket.OPEN) { socket.send(message); document.getElementById('chat-window').innerHTML += "發(fā)送消息: " + message + " "; document.getElementById('message').value = ""; } else { alert("WebSocket連接未建立或已關(guān)閉"); } } </script> </body> </html>
4.4 配置WebSocket端點(diǎn)
還需要在Spring Boot中配置WebSocket支持,確保端點(diǎn)被正確注冊:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean; @Configuration public class WebSocketConfig { @Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); container.setMaxTextMessageBufferSize(8192); container.setMaxBinaryMessageBufferSize(8192); return container; } }
這種基于注解的實(shí)現(xiàn)方式相比傳統(tǒng)接口方式更加簡潔直觀,通過注解即可完成WebSocket連接的生命周期管理和消息處理。
五、應(yīng)用場景拓展
5.1 實(shí)時(shí)數(shù)據(jù)推送
在股票交易、天氣監(jiān)測等場景中,服務(wù)器需要實(shí)時(shí)向客戶端推送數(shù)據(jù)??梢越Y(jié)合定時(shí)任務(wù)實(shí)現(xiàn):
@Service public class RealTimeDataService { @Autowired private SimpMessagingTemplate messagingTemplate; @Scheduled(fixedRate = 5000) // 每5秒執(zhí)行一次 public void pushRealTimeData() { // 獲取實(shí)時(shí)數(shù)據(jù) StockData stockData = getStockData(); // 推送給訂閱了實(shí)時(shí)股票信息的客戶端 messagingTemplate.convertAndSend("/topic/stock", stockData); } private StockData getStockData() { // 模擬獲取股票數(shù)據(jù) return new StockData("000001", "平安銀行", 15.68, 0.23); } }
5.2 在線協(xié)作編輯
多個(gè)用戶可以同時(shí)編輯同一個(gè)文檔,實(shí)時(shí)看到彼此的操作:
@MessageMapping("/edit") @SendTo("/topic/document/{docId}") public EditOperation handleEdit(@DestinationVariable String docId, EditOperation operation) { // 處理編輯操作,更新文檔 documentService.applyEdit(docId, operation); return operation; }
5.3 游戲?qū)崟r(shí)對戰(zhàn)
在在線游戲中,玩家的操作需要實(shí)時(shí)同步到其他玩家:
@MessageMapping("/game/{roomId}/move") public void handleGameMove(@DestinationVariable String roomId, MoveAction action) { // 更新游戲狀態(tài) gameService.updateGameState(roomId, action); // 廣播給房間內(nèi)的所有玩家 messagingTemplate.convertAndSend("/topic/game/" + roomId, action); }
六、性能優(yōu)化與最佳實(shí)踐
6.1 連接管理
- 使用連接池管理WebSocket連接,避免頻繁創(chuàng)建和銷毀連接
- 對長時(shí)間不活躍的連接進(jìn)行心跳檢測和自動(dòng)關(guān)閉
- 限制單個(gè)客戶端的連接數(shù)量,防止惡意連接
6.2 消息處理優(yōu)化
- 對高頻消息進(jìn)行合并和批處理,減少網(wǎng)絡(luò)開銷
- 使用異步處理機(jī)制,避免阻塞主線程
- 對大消息進(jìn)行分片傳輸,防止消息過大導(dǎo)致的性能問題
6.3 安全加固
- 使用SSL/TLS加密WebSocket連接,確保數(shù)據(jù)傳輸安全
- 實(shí)現(xiàn)嚴(yán)格的身份認(rèn)證和權(quán)限控制
- 對客戶端輸入進(jìn)行過濾和驗(yàn)證,防止XSS和SQL注入攻擊
6.4 監(jiān)控與告警
- 監(jiān)控WebSocket連接數(shù)、消息吞吐量等指標(biāo)
- 設(shè)置異常告警機(jī)制,及時(shí)發(fā)現(xiàn)和處理連接異常和性能問題
七、常見問題與解決方案
7.1 跨域問題
- 配置CORS允許WebSocket端點(diǎn)的跨域訪問
registry.addEndpoint("/websocket-endpoint") .setAllowedOrigins("*") .withSockJS();
7.2 消息丟失問題
- 實(shí)現(xiàn)消息確認(rèn)機(jī)制,確保消息可靠傳遞
- 使用持久化隊(duì)列存儲重要消息,防止服務(wù)器重啟導(dǎo)致消息丟失
7.3 性能瓶頸
- 分析性能瓶頸點(diǎn),針對性地進(jìn)行優(yōu)化
- 考慮使用分布式消息隊(duì)列和集群部署提高系統(tǒng)吞吐量
八、總結(jié)
本文從WebSocket的基礎(chǔ)概念出發(fā),詳細(xì)介紹了Spring Boot集成WebSocket的步驟,并重點(diǎn)講解了常用的使用方法,包括簡單消息收發(fā)、點(diǎn)對點(diǎn)消息發(fā)送、消息攔截與認(rèn)證,以及不使用接口而是基于注解的WebSocket實(shí)現(xiàn)方式。同時(shí),還拓展了WebSocket在不同場景下的應(yīng)用,提供了性能優(yōu)化建議和常見問題解決方案。
通過這些方法,開發(fā)者可以根據(jù)實(shí)際需求,靈活運(yùn)用WebSocket在Spring Boot應(yīng)用中實(shí)現(xiàn)高效的實(shí)時(shí)通信功能。在實(shí)際項(xiàng)目中,還可以結(jié)合更多的Spring Boot特性和業(yè)務(wù)邏輯,進(jìn)一步擴(kuò)展和優(yōu)化WebSocket的應(yīng)用,打造出更強(qiáng)大、更實(shí)用的實(shí)時(shí)應(yīng)用程序。
以上補(bǔ)充內(nèi)容完善了基于注解的WebSocket實(shí)現(xiàn)方案,并新增了應(yīng)用場景拓展、性能優(yōu)化等實(shí)用內(nèi)容。如需進(jìn)一步深入探討某個(gè)主題,或需要其他補(bǔ)充,請隨時(shí)告知。
到此這篇關(guān)于Spring Boot中WebSocket常用使用方法詳解的文章就介紹到這了,更多相關(guān)springboot websocket使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot使用WebSocket實(shí)現(xiàn)向前端推送消息功能
- WebSocket+Vue+SpringBoot實(shí)現(xiàn)語音通話的使用示例
- SpringBoot中使用WebSocket的教程分享
- 使用WebSocket+SpringBoot+Vue搭建簡易網(wǎng)頁聊天室的實(shí)現(xiàn)代碼
- SpringBoot使用WebSocket實(shí)現(xiàn)前后端交互的操作方法
- springboot?使用websocket技術(shù)主動(dòng)給前端發(fā)送消息的實(shí)現(xiàn)
- 使用springboot整合websocket實(shí)現(xiàn)群聊教程
- springboot整合websocket最基礎(chǔ)入門使用教程詳解
- websocket在springboot+vue中的使用教程
- SpringBoot使用WebSocket的方法實(shí)例詳解
相關(guān)文章
Java的Struts框架中<results>標(biāo)簽的使用方法
這篇文章主要介紹了Java的Struts框架中<results>標(biāo)簽的使用方法,Struts框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-11-11詳解Spring 框架中切入點(diǎn) pointcut 表達(dá)式的常用寫法
這篇文章主要介紹了詳解Spring 框架中切入點(diǎn) pointcut 表達(dá)式的常用寫法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04基于Spring Boot應(yīng)用ApplicationEvent案例場景
這篇文章主要介紹了基于Spring Boot應(yīng)用ApplicationEvent,利用Spring的機(jī)制發(fā)布ApplicationEvent和監(jiān)聽ApplicationEvent,需要的朋友可以參考下2023-03-03Spring常用注解及http數(shù)據(jù)轉(zhuǎn)換教程
這篇文章主要為大家介紹了Spring常用注解及http數(shù)據(jù)轉(zhuǎn)換原理以及接收復(fù)雜嵌套對象參數(shù)與Http數(shù)據(jù)轉(zhuǎn)換的原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03Java實(shí)戰(zhàn)之課程在線學(xué)習(xí)系統(tǒng)的實(shí)現(xiàn)
本文將采用SpringBoot+Spring+Mybatis+Thyeleaf實(shí)現(xiàn)一個(gè)課程在線學(xué)習(xí)系統(tǒng),采用SpringBoot框架實(shí)現(xiàn)?前臺模板用的thymeleaf數(shù)據(jù)庫層采用mybatis框架注解模式,感興趣的可以了解一下2022-04-04關(guān)于replaceFirst使用時(shí)的注意事項(xiàng)
這篇文章主要介紹了關(guān)于replaceFirst使用時(shí)的注意事項(xiàng),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03springboot構(gòu)造樹形結(jié)構(gòu)數(shù)據(jù)并查詢的方法
本文主要介紹了springboot怎樣構(gòu)造樹形結(jié)構(gòu)數(shù)據(jù)并查詢,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11