最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot2.0集成WebSocket實(shí)現(xiàn)后臺(tái)向前端推送信息

 更新時(shí)間:2021年01月24日 11:43:02   作者:Moshow鄭鍇  
這篇文章主要介紹了SpringBoot2.0集成WebSocket實(shí)現(xiàn)后臺(tái)向前端推送信息,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

什么是WebSocket?

這里寫圖片描述

WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工(full-duplex)通信——允許服務(wù)器主動(dòng)發(fā)送信息給客戶端。

為什么需要 WebSocket?

初次接觸 WebSocket 的人,都會(huì)問同樣的問題:我們已經(jīng)有了 HTTP 協(xié)議,為什么還需要另一個(gè)協(xié)議?它能帶來什么好處?

答案很簡(jiǎn)單,因?yàn)?HTTP 協(xié)議有一個(gè)缺陷:通信只能由客戶端發(fā)起,HTTP 協(xié)議做不到服務(wù)器主動(dòng)向客戶端推送信息。

這里寫圖片描述

舉例來說,我們想要查詢當(dāng)前的排隊(duì)情況,只能是頁面輪詢向服務(wù)器發(fā)出請(qǐng)求,服務(wù)器返回查詢結(jié)果。輪詢的效率低,非常浪費(fèi)資源(因?yàn)楸仨毑煌_B接,或者 HTTP 連接始終打開)。因此WebSocket 就是這樣發(fā)明的。 前言

2020-10-20 教程補(bǔ)充:

  • 補(bǔ)充關(guān)于@Component@ServerEndpoint關(guān)于是否單例模式等的解答,感謝大家熱心提問和研究。
  • Vue版本的websocket連接方法

2020-01-05 教程補(bǔ)充:

  • 整合了IM相關(guān)的優(yōu)化
  • 優(yōu)化開啟/關(guān)閉連接的處理
  • 上傳到開源項(xiàng)目spring-cloud-study-websocket,方便大家下載代碼。

感謝大家的支持和留言,14W訪問量是滿滿的動(dòng)力!接下來還會(huì)有websocket+redis集群優(yōu)化篇針對(duì)多ws服務(wù)器做簡(jiǎn)單優(yōu)化處理,敬請(qǐng)期待!

話不多說,馬上進(jìn)入干貨時(shí)刻。

maven依賴

SpringBoot2.0對(duì)WebSocket的支持簡(jiǎn)直太棒了,直接就有包可以引入

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 開啟WebSocket支持
 * @author zhengkai.blog.csdn.net
 */
@Configuration 
public class WebSocketConfig { 
	
 @Bean 
 public ServerEndpointExporter serverEndpointExporter() { 
 return new ServerEndpointExporter(); 
 } 
 
} 

WebSocketConfig

啟用WebSocket的支持也是很簡(jiǎn)單,幾句代碼搞定

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/** * 開啟WebSocket支持 * @author zhengkai.blog.csdn.net */@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } 

WebSocketServer

這就是重點(diǎn)了,核心都在這里。

  • 因?yàn)閃ebSocket是類似客戶端服務(wù)端的形式(采用ws協(xié)議),那么這里的WebSocketServer其實(shí)就相當(dāng)于一個(gè)ws協(xié)議的Controller
  • 直接@ServerEndpoint("/imserver/{userId}") 、@Component啟用即可,然后在里面實(shí)現(xiàn)@OnOpen開啟連接,@onClose關(guān)閉連接,@onMessage接收消息等方法。
  • 新建一個(gè)ConcurrentHashMap webSocketMap 用于接收當(dāng)前userId的WebSocket,方便IM之間對(duì)userId進(jìn)行推送消息。單機(jī)版實(shí)現(xiàn)到這里就可以。
  • 集群版(多個(gè)ws節(jié)點(diǎn))還需要借助mysql或者redis等進(jìn)行處理,改造對(duì)應(yīng)的sendMessage方法即可。
package com.softdev.system.demo.config;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;


/**
 * @author zhengkai.blog.csdn.net
 */
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {

 static Log log=LogFactory.get(WebSocketServer.class);
 /**靜態(tài)變量,用來記錄當(dāng)前在線連接數(shù)。應(yīng)該把它設(shè)計(jì)成線程安全的。*/
 private static int onlineCount = 0;
 /**concurrent包的線程安全Set,用來存放每個(gè)客戶端對(duì)應(yīng)的MyWebSocket對(duì)象。*/
 private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
 /**與某個(gè)客戶端的連接會(huì)話,需要通過它來給客戶端發(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;
 if(webSocketMap.containsKey(userId)){
 webSocketMap.remove(userId);
 webSocketMap.put(userId,this);
 //加入set中
 }else{
 webSocketMap.put(userId,this);
 //加入set中
 addOnlineCount();
 //在線數(shù)加1
 }

 log.info("用戶連接:"+userId+",當(dāng)前在線人數(shù)為:" + getOnlineCount());

 try {
 sendMessage("連接成功");
 } catch (IOException e) {
 log.error("用戶:"+userId+",網(wǎng)絡(luò)異常!!!!!!");
 }
 }

 /**
 * 連接關(guān)閉調(diào)用的方法
 */
 @OnClose
 public void onClose() {
 if(webSocketMap.containsKey(userId)){
 webSocketMap.remove(userId);
 //從set中刪除
 subOnlineCount();
 }
 log.info("用戶退出:"+userId+",當(dāng)前在線人數(shù)為:" + getOnlineCount());
 }

 /**
 * 收到客戶端消息后調(diào)用的方法
 *
 * @param message 客戶端發(fā)送過來的消息*/
 @OnMessage
 public void onMessage(String message, Session session) {
 log.info("用戶消息:"+userId+",報(bào)文:"+message);
 //可以群發(fā)消息
 //消息保存到數(shù)據(jù)庫、redis
 if(StringUtils.isNotBlank(message)){
 try {
 //解析發(fā)送的報(bào)文
 JSONObject jsonObject = JSON.parseObject(message);
 //追加發(fā)送人(防止串改)
 jsonObject.put("fromUserId",this.userId);
 String toUserId=jsonObject.getString("toUserId");
 //傳送給對(duì)應(yīng)toUserId用戶的websocket
 if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){
 webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
 }else{
 log.error("請(qǐng)求的userId:"+toUserId+"不在該服務(wù)器上");
 //否則不在這個(gè)服務(wù)器上,發(fā)送到mysql或者redis
 }
 }catch (Exception e){
 e.printStackTrace();
 }
 }
 }

 /**
 *
 * @param session
 * @param error
 */
 @OnError
 public void onError(Session session, Throwable error) {
 log.error("用戶錯(cuò)誤:"+this.userId+",原因:"+error.getMessage());
 error.printStackTrace();
 }
 /**
 * 實(shí)現(xiàn)服務(wù)器主動(dòng)推送
 */
 public void sendMessage(String message) throws IOException {
 this.session.getBasicRemote().sendText(message);
 }


 /**
 * 發(fā)送自定義消息
 * */
 public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
 log.info("發(fā)送消息到:"+userId+",報(bào)文:"+message);
 if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
 webSocketMap.get(userId).sendMessage(message);
 }else{
 log.error("用戶"+userId+",不在線!");
 }
 }

 public static synchronized int getOnlineCount() {
 return onlineCount;
 }

 public static synchronized void addOnlineCount() {
 WebSocketServer.onlineCount++;
 }

 public static synchronized void subOnlineCount() {
 WebSocketServer.onlineCount--;
 }
}

消息推送

至于推送新信息,可以再自己的Controller寫個(gè)方法調(diào)用WebSocketServer.sendInfo();即可

import com.softdev.system.demo.config.WebSocketServer;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;

/**
 * WebSocketController
 * @author zhengkai.blog.csdn.net
 */
@RestController
public class DemoController {

 @GetMapping("index")
 public ResponseEntity<String> index(){
 return ResponseEntity.ok("請(qǐng)求成功");
 }

 @GetMapping("page")
 public ModelAndView page(){
 return new ModelAndView("websocket");
 }

 @RequestMapping("/push/{toUserId}")
 public ResponseEntity<String> pushToWeb(String message, @PathVariable String toUserId) throws IOException {
 WebSocketServer.sendInfo(message,toUserId);
 return ResponseEntity.ok("MSG SEND SUCCESS");
 }
}

頁面發(fā)起

頁面用js代碼調(diào)用websocket,當(dāng)然,太古老的瀏覽器是不行的,一般新的瀏覽器或者谷歌瀏覽器是沒問題的。還有一點(diǎn),記得協(xié)議是ws的,如果使用了一些路徑類,可以replace(“http”,“ws”)來替換協(xié)議。

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <title>websocket通訊</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
 var socket;
 function openSocket() {
 if(typeof(WebSocket) == "undefined") {
 console.log("您的瀏覽器不支持WebSocket");
 }else{
 console.log("您的瀏覽器支持WebSocket");
 //實(shí)現(xiàn)化WebSocket對(duì)象,指定要連接的服務(wù)器地址與端口 建立連接
 //等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
 //var socketUrl="${request.contextPath}/im/"+$("#userId").val();
 var socketUrl="http://localhost:9999/demo/imserver/"+$("#userId").val();
 socketUrl=socketUrl.replace("https","ws").replace("http","ws");
 console.log(socketUrl);
 if(socket!=null){
 socket.close();
 socket=null;
 }
 socket = new WebSocket(socketUrl);
 //打開事件
 socket.onopen = function() {
 console.log("websocket已打開");
 //socket.send("這是來自客戶端的消息" + location.href + new Date());
 };
 //獲得消息事件
 socket.onmessage = function(msg) {
 console.log(msg.data);
 //發(fā)現(xiàn)消息進(jìn)入 開始處理前端觸發(fā)邏輯
 };
 //關(guān)閉事件
 socket.onclose = function() {
 console.log("websocket已關(guān)閉");
 };
 //發(fā)生了錯(cuò)誤事件
 socket.onerror = function() {
 console.log("websocket發(fā)生了錯(cuò)誤");
 }
 }
 }
 function sendMessage() {
 if(typeof(WebSocket) == "undefined") {
 console.log("您的瀏覽器不支持WebSocket");
 }else {
 console.log("您的瀏覽器支持WebSocket");
 console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
 socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
 }
 }
</script>
<body>
<p>【userId】:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>【toUserId】:<div><input id="toUserId" name="toUserId" type="text" value="20"></div>
<p>【toUserId】:<div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【操作】:<div><a onclick="openSocket()">開啟socket</a></div>
<p>【操作】:<div><a onclick="sendMessage()">發(fā)送消息</a></div>
</body>

</html>

運(yùn)行效果

  • v20200105,加入開源項(xiàng)目spring-cloud-study-websocket,更新運(yùn)行效果,更方便理解。
  • v1.1的效果,剛剛修復(fù)了日志,并且支持指定監(jiān)聽某個(gè)端口,代碼已經(jīng)全部更新,現(xiàn)在是這樣的效果

打開兩個(gè)頁面,按F12調(diào)出控控制臺(tái)查看測(cè)試效果:

頁面 參數(shù)
http://localhost:9999/demo/page fromUserId=10,toUserId=20
http://localhost:9999/demo/page fromUserId=20,toUserId=10

分別開啟socket,再發(fā)送消息

在這里插入圖片描述
在這里插入圖片描述

2. 向前端推送數(shù)據(jù):

http://localhost:9999/demo/push/10?message=123123

在這里插入圖片描述

通過調(diào)用push api,可以向指定的userId推送信息,當(dāng)然報(bào)文這里亂寫,建議規(guī)定好格式。

后續(xù)

針對(duì)簡(jiǎn)單IM的業(yè)務(wù)場(chǎng)景,進(jìn)行了一些優(yōu)化,可以看后續(xù)的文章SpringBoot2+WebSocket之聊天應(yīng)用實(shí)戰(zhàn)(優(yōu)化版本)(v20201005已整合)

主要變動(dòng)是CopyOnWriteArraySet改為ConcurrentHashMap,保證多線程安全同時(shí)方便利用map.get(userId)進(jìn)行推送到指定端口。

相比之前的Set,Set遍歷是費(fèi)事且麻煩的事情,而Map的get是簡(jiǎn)單便捷的,當(dāng)WebSocket數(shù)量大的時(shí)候,這個(gè)小小的消耗就會(huì)聚少成多,影響體驗(yàn),所以需要優(yōu)化。在IM的場(chǎng)景下,指定userId進(jìn)行推送消息更加方便。

Websocker注入Bean問題

關(guān)于這個(gè)問題,可以看最新發(fā)表的這篇文章,在參考和研究了網(wǎng)上一些攻略后,項(xiàng)目已經(jīng)通過該方法注入成功,大家可以參考。
Springboot 使用 JSR 303 對(duì) Controller 控制層校驗(yàn)及 Service 服務(wù)層 AOP 校驗(yàn) 使用消息資源文件對(duì)消息國際化

netty-websocket-spring-boot-starter

Springboot2構(gòu)建基于Netty的高性能Websocket服務(wù)器(netty-websocket-spring-boot-starter)
只需要換個(gè)starter即可實(shí)現(xiàn)高性能websocket,趕緊使用吧

Springboot2+Netty+Websocket

Springboot2+Netty實(shí)現(xiàn)Websocket,使用官方的netty-all的包,比原生的websocket更加穩(wěn)定更加高性能,同等配置情況下可以handle更多的連接。

代碼樣式全部已經(jīng)更正,也支持websocket連接url帶參數(shù)功能,另外也感謝大家的閱讀和評(píng)論,一起進(jìn)步,謝謝!~~

ServerEndpointExporter錯(cuò)誤

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘serverEndpointExporter' defined in class path resource [com/xxx/WebSocketConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available

感謝@來了老弟兒 的反饋:

如果tomcat部署一直報(bào)這個(gè)錯(cuò),請(qǐng)移除 WebSocketConfig@Bean ServerEndpointExporter 的注入 。

ServerEndpointExporter 是由Spring官方提供的標(biāo)準(zhǔn)實(shí)現(xiàn),用于掃描ServerEndpointConfig配置類和@ServerEndpoint注解實(shí)例。使用規(guī)則也很簡(jiǎn)單:

如果使用默認(rèn)的嵌入式容器 比如Tomcat 則必須手工在上下文提供ServerEndpointExporter。如果使用外部容器部署war包,則不需要提供提供ServerEndpointExporter,因?yàn)榇藭r(shí)SpringBoot默認(rèn)將掃描服務(wù)端的行為交給外部容器處理,所以線上部署的時(shí)候要把WebSocketConfig中這段注入bean的代碼注掉。 正式項(xiàng)目的前端WebSocket框架 GoEasy

感謝kkatrina的補(bǔ)充,正式的項(xiàng)目中,一般是用第三方websocket框架來做,穩(wěn)定性、實(shí)時(shí)性有保證的多,也會(huì)包括一些心跳、重連機(jī)制。

GoEasy專注于服務(wù)器與瀏覽器,瀏覽器與瀏覽器之間消息推送,完美兼容世界上的絕大多數(shù)瀏覽器,包括IE6, IE7之類的非常古老的瀏覽器。支持Uniapp,各種小程序,react,vue等所有主流Web前端技術(shù)。
GoEasy采用 發(fā)布/訂閱 的消息模式,幫助您非常輕松的實(shí)現(xiàn)一對(duì)一,一對(duì)多的通信。
https://www.goeasy.io/cn/doc/

@Component@ServerEndpoint關(guān)于是否單例模式,能否使用static Map等一些問題的解答

看到大家都在熱心的討論關(guān)于是否單例模式這個(gè)問題,請(qǐng)大家相信自己的直接,如果websocket是單例模式,還怎么服務(wù)這么多session呢。

  • websocket是原型模式,@ServerEndpoint每次建立雙向通信的時(shí)候都會(huì)創(chuàng)建一個(gè)實(shí)例,區(qū)別于spring的單例模式。Spring的@Component默認(rèn)是單例模式,請(qǐng)注意,默認(rèn) 而已,是可以被改變的。
  • 這里的@Component僅僅為了支持@Autowired依賴注入使用,如果不加則不能注入任何東西,為了方便。
  • 什么是prototype 原型模式? 基本就是你需要從A的實(shí)例得到一份與A內(nèi)容相同,但是又互不干擾的實(shí)例B的話,就需要使用原型模式。關(guān)于在原型模式下使用static 的webSocketMap,請(qǐng)注意這是ConcurrentHashMap ,也就是線程安全/線程同步的,而且已經(jīng)是靜態(tài)變量作為全局調(diào)用,這種情況下是ok的,或者大家如果有顧慮或者更好的想法的化,可以進(jìn)行改進(jìn)。
  • 例如使用一個(gè)中間類來接收和存放session。為什么每次都@OnOpen都要檢查webSocketMap.containsKey(userId) ,首先了為了代碼強(qiáng)壯性考慮,假設(shè)代碼以及機(jī)制沒有問題,那么肯定這個(gè)邏輯是廢的對(duì)吧。
  • 但是實(shí)際使用的時(shí)候發(fā)現(xiàn)偶爾會(huì)出現(xiàn)重連失敗或者其他原因?qū)е轮暗膕ession還存在,這里就做了一個(gè)清除舊session,迎接新session的功能。

Vue版本的websocket連接

感謝**@GzrStudy**的貢獻(xiàn),供大家參考。

<script>
export default {
 data() {
 return {
 socket:null,
 userId:localStorage.getItem("ms_uuid"),
 toUserId:'2',
 content:'3'
 }
 },
 methods: {
 openSocket() {
 if (typeof WebSocket == "undefined") {
 console.log("您的瀏覽器不支持WebSocket");
 } else {
 console.log("您的瀏覽器支持WebSocket");
 //實(shí)現(xiàn)化WebSocket對(duì)象,指定要連接的服務(wù)器地址與端口 建立連接
 //等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
 //var socketUrl="${request.contextPath}/im/"+$("#userId").val();
 var socketUrl =
 "http://localhost:8081/imserver/" + this.userId;
 socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");
 console.log(socketUrl);
 if (this.socket != null) {
 this.socket.close();
 this.socket = null;
 }
 this.socket = new WebSocket(socketUrl);
 //打開事件
 this.socket = new WebSocket(socketUrl);
 //打開事件
 this.socket.onopen = function() {
 console.log("websocket已打開");
 //socket.send("這是來自客戶端的消息" + location.href + new Date());
 };
 //獲得消息事件
 this.socket.onmessage = function(msg) {
 console.log(msg.data);
 //發(fā)現(xiàn)消息進(jìn)入 開始處理前端觸發(fā)邏輯
 };
 //關(guān)閉事件
 this.socket.onclose = function() {
 console.log("websocket已關(guān)閉");
 };
 //發(fā)生了錯(cuò)誤事件
 this.socket.onerror = function() {
 console.log("websocket發(fā)生了錯(cuò)誤");
 };
 }
 },
 sendMessage() {
 if (typeof WebSocket == "undefined") {
 console.log("您的瀏覽器不支持WebSocket");
 } else {
 console.log("您的瀏覽器支持WebSocket");
 console.log(
 '{"toUserId":"' +
 this.toUserId +
 '","contentText":"' +
 this.content +
 '"}'
 );
 this.socket.send(
 '{"toUserId":"' +
 this.toUserId +
 '","contentText":"' +
 this.content +
 '"}'
 );
 
 }
}

到此這篇關(guān)于SpringBoot2.0集成WebSocket實(shí)現(xiàn)后臺(tái)向前端推送信息的文章就介紹到這了,更多相關(guān)SpringBoot2.0集成WebSocket內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • RestTemplate報(bào)錯(cuò)400 Bad Request的解決方案

    RestTemplate報(bào)錯(cuò)400 Bad Request的解決方案

    在使用Spring Boot時(shí),若直接通過@Autowired注入RestTemplate可能會(huì)遇到400BadRequest錯(cuò)誤,原因在于Spring Boot官方文檔指出,由于RestTemplate實(shí)例通常需要在使用前進(jìn)行定制,因此Spring Boot不會(huì)自動(dòng)配置單個(gè)RestTemplate Bean
    2024-11-11
  • SpringBoot3 響應(yīng)式網(wǎng)絡(luò)請(qǐng)求客戶端的實(shí)現(xiàn)

    SpringBoot3 響應(yīng)式網(wǎng)絡(luò)請(qǐng)求客戶端的實(shí)現(xiàn)

    本文主要介紹了SpringBoot3 響應(yīng)式網(wǎng)絡(luò)請(qǐng)求客戶端的實(shí)現(xiàn),文章詳細(xì)闡述了如何使用SpringBoot3的網(wǎng)絡(luò)請(qǐng)求客戶端進(jìn)行HTTP請(qǐng)求和處理響應(yīng),并提供了示例代碼和說明,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • java實(shí)現(xiàn)輕輕松松控制臺(tái)斗地主的示例代碼

    java實(shí)現(xiàn)輕輕松松控制臺(tái)斗地主的示例代碼

    這篇文章主要介紹了java實(shí)現(xiàn)輕輕松松控制臺(tái)斗地主,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • java 判斷二進(jìn)制文件的方法

    java 判斷二進(jìn)制文件的方法

    這篇文章主要介紹了java 判斷二進(jìn)制文件的方法的相關(guān)資料,這里提供實(shí)例來實(shí)現(xiàn)判斷文件是否問二進(jìn)制文件,希望能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • IntelliJ IDEA中Project與Module的概念以及區(qū)別

    IntelliJ IDEA中Project與Module的概念以及區(qū)別

    這篇文章主要給大家介紹了關(guān)于IntelliJ IDEA中Project與Module的概念以及區(qū)別的相關(guān)資料,文中通過實(shí)例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • java中Map接口常用的方法解讀

    java中Map接口常用的方法解讀

    這篇文章主要介紹了java中Map接口常用的方法解讀,Map接口是雙列集合,它的每一個(gè)元素都包含一個(gè)鍵對(duì)象key和值對(duì)象Value,鍵和值對(duì)象之間存在一種對(duì)應(yīng)關(guān)系,稱為映射,需要的朋友可以參考下
    2024-01-01
  • Mybatis-Plus中的@TableName 和 table-prefix使用

    Mybatis-Plus中的@TableName 和 table-prefix使用

    table-prefix 是一個(gè)全局配置,它會(huì)自動(dòng)在所有表名前添加指定的前綴,這個(gè)配置對(duì)于那些使用一致命名約定的數(shù)據(jù)庫表非常有用,這篇文章主要介紹了Mybatis-Plus中的@TableName 和 table-prefix使用,需要的朋友可以參考下
    2024-08-08
  • Java關(guān)于JDK1.8新特性的Stream流

    Java關(guān)于JDK1.8新特性的Stream流

    這篇文章主要介紹了版本薇JDK1.8 的Java中的Stream流,Stream流是一個(gè)來自數(shù)據(jù)源的元素隊(duì)列并支持聚合操作,感興趣的朋友可以參考下面文章內(nèi)容
    2021-09-09
  • java8升級(jí)java21方法步驟(完整pom文件升級(jí)及代碼修改)

    java8升級(jí)java21方法步驟(完整pom文件升級(jí)及代碼修改)

    在從Java?8升級(jí)至Java?211的過程中,需要對(duì)多個(gè)POM文件進(jìn)行升級(jí),涉及parent、web、service等模塊,文中通過代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-11-11
  • Mybatis攔截器的實(shí)現(xiàn)介紹

    Mybatis攔截器的實(shí)現(xiàn)介紹

    MyBatis提供了一種插件(plugin)的功能,雖然叫做插件,但其實(shí)這是攔截器功能。MyBatis 允許你在已映射語句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用。下面通過本文給大家介紹Mybatis攔截器知識(shí),感興趣的朋友一起看看吧
    2016-10-10

最新評(píng)論

通化县| 农安县| 微山县| 平邑县| 屏东县| 五原县| 印江| 昌乐县| 米脂县| 惠水县| 新龙县| 宁乡县| 乐平市| 犍为县| 武威市| 乌兰察布市| 榆社县| 台东县| 永川市| 永胜县| 苗栗市| 台安县| 江安县| 牡丹江市| 高碑店市| 芒康县| 彭泽县| 安康市| 福清市| 姜堰市| 南郑县| 平潭县| 尖扎县| 九龙县| 潞城市| 苍溪县| 高青县| 宁强县| 太仓市| 漯河市| 德江县|