淺談cookie和session(小結(jié))
cookie和session在java web開發(fā)中扮演了十分重要的作用,本篇文章對其中的重要知識(shí)點(diǎn)做一些探究和總結(jié)。
1.cookie存在于瀏覽器
隨意打開一個(gè)網(wǎng)址,用火狐的調(diào)試工具,隨意選取一個(gè)鏈接,查看其請求頭。你就會(huì)看到cookie的信息。如下圖所示。

如上圖所示,我們訪問了新浪網(wǎng),通過火狐瀏覽器的調(diào)試窗口可以看到cookie存在于請求頭也就是httprequest中,并且是以鍵值對(數(shù)組)的形式存在。
只要有請求,就會(huì)在請求頭攜帶一個(gè)cookie的數(shù)組(鍵值對)。cookie是瀏覽器層面的東西。
2.java中獲取cookie
事實(shí)上,在java的servlet體系里,我們可以通過如下方式獲取cookie.
HttpServletRequest req=ServletActionContext.getRequest();
Cookie[] cookies=req.getCookies();
for(int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
System.out.println("name:"+cookie.getName()+",domain"+cookie.getDomain()+",value:"+cookie.getValue()+",maxage:"+cookie.getMaxAge());
}
可以看到,在servlet體系中,把cookie作為一個(gè)屬性放到了HttpRequest對象里面。通過getCookies()方法得到一個(gè)cookie數(shù)組。
我們在一個(gè)action中加入上述代碼,并且訪問這個(gè)action,則可以看到控制臺(tái)打印出如下信息。

servlet對cookie進(jìn)行了封裝,cookie對象有幾個(gè)屬性,如name,domain,value,maxage等,具體的意義可以參考servlet的api文檔。
以上的請求的cookie是我首次訪問某一個(gè)網(wǎng)站的鏈接時(shí)候產(chǎn)生的。可以看到cookie數(shù)組中只有一個(gè)元素。這邊先注意一下,后續(xù)會(huì)有更進(jìn)一步的說明。
3.java中向cookie中添加元素
說了獲取cookie數(shù)組和cookie,我們一定也想知道如何把我們自己的一些信息放進(jìn)cookie,其實(shí)很簡單。http的一次請求總是伴隨著一次響應(yīng),我們就將cookie信息放入到響應(yīng)中,傳遞給瀏覽器。在java下代碼是這樣寫的。
HttpServletResponse res=ServletActionContext.getResponse();
Cookie cookie=new Cookie("xdx", "i'm xdx");
res.addCookie(cookie);
可以看到當(dāng)我們發(fā)起這個(gè)請求時(shí),在響應(yīng)頭有下列信息。

也就是通過這次請求,我們把xdx=i'm xdx 這個(gè)cookie通過response放進(jìn)了瀏覽器。
當(dāng)我們再次訪問該網(wǎng)站上的其他頁面的時(shí)候,在請求頭都將帶有這個(gè)cookie。如下圖所示。

而假如我們清除歷史記錄,包括cookie。

再次訪問該網(wǎng)站的某一個(gè)地址。剛才我們加進(jìn)去的cookie就不存在了。

總結(jié)來說就是:servlet通過response將cookie放入到cookie數(shù)組中,這樣瀏覽器端就會(huì)擁有這一個(gè)cookie信息。瀏覽器會(huì)在以后的請求過程中把這個(gè)cookie信息放在請求頭。
4.session是什么
session我們一般指的是HTTPSession,為了理解它,我們直接打開HttpSession的源碼來一看究竟。
/**
*
* Provides a way to identify a user across more than one page
* request or visit to a Web site and to store information about that user.
*
* <p>The servlet container uses this interface to create a session
* between an HTTP client and an HTTP server. The session persists
* for a specified time period, across more than one connection or
* page request from the user. A session usually corresponds to one
* user, who may visit a site many times. The server can maintain a
* session in many ways such as using cookies or rewriting URLs.
*
* <p>This interface allows servlets to
* <ul>
* <li>View and manipulate information about a session, such as
* the session identifier, creation time, and last accessed time
* <li>Bind objects to sessions, allowing user information to persist
* across multiple user connections
* </ul>
*
* <p>When an application stores an object in or removes an object from a
* session, the session checks whether the object implements
* {@link HttpSessionBindingListener}. If it does,
* the servlet notifies the object that it has been bound to or unbound
* from the session. Notifications are sent after the binding methods complete.
* For session that are invalidated or expire, notifications are sent after
* the session has been invalidated or expired.
*
* <p> When container migrates a session between VMs in a distributed container
* setting, all session attributes implementing the {@link HttpSessionActivationListener}
* interface are notified.
*
* <p>A servlet should be able to handle cases in which
* the client does not choose to join a session, such as when cookies are
* intentionally turned off. Until the client joins the session,
* <code>isNew</code> returns <code>true</code>. If the client chooses
* not to join
* the session, <code>getSession</code> will return a different session
* on each request, and <code>isNew</code> will always return
* <code>true</code>.
*
* <p>Session information is scoped only to the current web application
* (<code>ServletContext</code>), so information stored in one context
* will not be directly visible in another.
*
* @author Various
*
* @see HttpSessionBindingListener
* @see HttpSessionContext
簡單的翻譯一下:
--提供一個(gè)在多頁面請求切換的情況下用于驗(yàn)證、存儲(chǔ)用戶信息的手段。
--servlet容器使用Httpsession來創(chuàng)建連接客戶端和服務(wù)端的一個(gè)會(huì)話(session)。這個(gè)會(huì)話能持續(xù)一段指定的時(shí)間(也就是我們常說的session過期時(shí)間),該會(huì)話能在多個(gè)請求之間共享。
--這個(gè)會(huì)話一般跟用戶信息關(guān)聯(lián),由于這個(gè)用戶可能多次訪問網(wǎng)站,所以我們把他們存儲(chǔ)在這個(gè)會(huì)話(也就是httpsession)里。
--服務(wù)端通常是通過cookies或者rewriting URLs來保持一個(gè)session。
我的理解,session是一種持久的會(huì)話,它的存在主要是為了克服http無狀態(tài)的特點(diǎn),關(guān)于http無狀態(tài),或者說沒有記憶,這里不多闡述,涉及到計(jì)算機(jī)網(wǎng)絡(luò)的知識(shí),簡單來說就是http一次請求對應(yīng)一次響應(yīng),在這個(gè)過程中會(huì)攜帶一些信息,但這些信息也僅僅在這個(gè)過程中有效。當(dāng)一個(gè)請求結(jié)束,我們進(jìn)入下一個(gè)請求的時(shí)候,上一個(gè)請求里面的信息對當(dāng)前的請求就沒什么意義了,因?yàn)楫?dāng)前的請求根本不會(huì)知道上一個(gè)請求里面所包含的信息。
那么當(dāng)我們需要一些在各個(gè)請求都能公用的信息的時(shí)候,該怎么辦呢?有很多辦法,可以把信息存在數(shù)據(jù)庫,然后每次從數(shù)據(jù)庫去取出來,當(dāng)然io存取會(huì)浪費(fèi)很多時(shí)間,它僅僅針對大數(shù)據(jù)量。還有一種就是將這些信息存在內(nèi)存當(dāng)中。沒錯(cuò)session其實(shí)就是這樣一種對象,他把項(xiàng)目當(dāng)中一些常用的信息存在內(nèi)存當(dāng)中,這些常用的信息通常是跟用戶相關(guān)的,比如用戶名,用戶昵稱,用戶角色等。因?yàn)樗麄冃枰?jīng)常用到,所以把這些信息存在session中進(jìn)行管理再好不過了。
5.如何獲取一個(gè)session
在servlet體系里,我們可以用如下代碼來獲取session。
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession httpSession=request.getSession();
System.out.println(httpSession);
我們來查閱HttpServletRequest的源碼,看看其getSession()方法。
/** * * Returns the current session associated with this request, * or if the request does not have a session, creates one. * * @return the <code>HttpSession</code> associated * with this request * * @see #getSession(boolean) * */ public HttpSession getSession();
它的解釋是返回當(dāng)前與request關(guān)聯(lián)的session,如果這個(gè)請求不存在session,就新建一個(gè)。
我們在兩個(gè)請求中加入上述代碼并運(yùn)行,得到如下結(jié)果。

可以看到在整個(gè)項(xiàng)目內(nèi),這個(gè)session被共享著調(diào)用。
6.session和cookie到底有什么關(guān)系呢?
簡單點(diǎn)說,每一個(gè)session對象都有一個(gè)sessionId,而在cookie數(shù)組中,又一個(gè)元素叫做JSESSIONID,服務(wù)器將session對象的sessionId,以名稱叫做JSESSIONID,值為sessionId的形式存入cookie數(shù)組中,這樣cookie和session就發(fā)生了關(guān)聯(lián)。
上面的描述可以用下圖來表示。

上述的過程可以用類似如下的代碼來實(shí)現(xiàn)。
HttpServletRequest req=ServletActionContext.getRequest();
HttpServletResponse res=ServletActionContext.getResponse();
Cookie cookie=new Cookie("JSESSIONID", req.getSession().getId());
res.addCookie(cookie);
只不過我們并不需要寫這個(gè)代碼,servlet自動(dòng)幫我們完成了如上的操作。
7.具體過程
具體的過程是這樣的:
(1)當(dāng)我們首次在某個(gè)請求中通過調(diào)用request.getSession去獲取session的時(shí)候(這個(gè)調(diào)用不一定是顯式的,很多框架把session封裝成map等其他的類型,名稱也不一定是session,但是本質(zhì)都是在調(diào)用session),首先servlet通過getCookie的到本次請求的cookie信息,然后去尋找cookie數(shù)組中是否有否有一個(gè)名為JSESSIONID的cookie,沒有的話就創(chuàng)建一個(gè)session,并且把sessionId做為JSESSIONID這個(gè)cookie的值,然后調(diào)用addCookie()方法把該cookie放入cookie數(shù)組。
(2)如果上一步中從cookie數(shù)組中取到的cookie數(shù)組已經(jīng)包含了JSESSIONID這個(gè)cookie,這時(shí)候我我們?nèi)〕鯦SESSIONID的值,然后去內(nèi)存中的session(內(nèi)存中有很多session)去尋找對應(yīng)的sessionId為JSESSIONID的值的session,如果找得到的話,就使用這個(gè)session,找不到的話,就新建一個(gè)session,并且同樣的調(diào)用addCookie()方法覆蓋掉原來的JSESSIONID這個(gè)cookie的值。
上述的過程可以用類似如下的代碼來表示。
HttpServletRequest req=ServletActionContext.getRequest();//具體獲取request的情況可能有所不同
HttpSession session;
Cookie JSESSIONID=null;
Cookie[] cookies=req.getCookies();
for(int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
if(cookie.getName().equals("JSESSIONID")){
JSESSIONID=cookie;
}
}
if(JSESSIONID==null){
session= createSession();//創(chuàng)建一個(gè)session
}else{
session=findSessionBySessionId(JSESSIONID.getValue());//通過sessionId獲取session
if(session==null){
session= createSession();//創(chuàng)建一個(gè)session
}
HttpServletRequest req=ServletActionContext.getResponse();//具體情況可能有所不同
Cookie cookie=new Cookie("JSESSIONID", session.getId());
res.addCookie(cookie);
我們將瀏覽器緩存清除,這樣cookie中就沒有JSESSIONID了,然后我們訪問一個(gè)action。如下。
8.當(dāng)我們清空瀏覽器的時(shí)候,session會(huì)消失嗎?
這個(gè)問題包含著一些陷阱。因?yàn)楹芏鄷r(shí)候當(dāng)我們清空瀏覽器以后,確實(shí)需要重新登錄系統(tǒng)才可以操作,所以很多人自然而然認(rèn)為清空瀏覽器緩存(包含cookie)以后。session就會(huì)消失。
其實(shí)這種結(jié)論是錯(cuò)誤的。要知道,session是存在于服務(wù)器的,你清除瀏覽器緩存,只是清除了cookie,跟session一點(diǎn)關(guān)系都沒有。那么為什么我們卻不能訪問網(wǎng)站,而需要重新登錄了呢?
一般的web項(xiàng)目會(huì)通過session來判斷用戶是否有登錄,常用的判斷語句是if(session.get("userId")==null。如果為空,則表示需要重新登錄。這時(shí)候其實(shí)隱式地調(diào)用了getSession()方法,這就回到了上一步我們所講的session獲取的具體步驟了。
因?yàn)榍蹇樟藶g覽器緩存,這時(shí)候cookie數(shù)組中必定不會(huì)有JSESSIONID這個(gè)cookie,所以必須得新建一個(gè)session,用新的sessionId來給JSESSIONID這個(gè)cookie賦值。由于是新建的session,session中必定沒有userId這樣的屬性值,所以判斷結(jié)果自然為空,所以需要重新登錄。這次賦值以后,下一次再請求該網(wǎng)站的時(shí)候,由于cookie數(shù)組中已經(jīng)有了JSESSIONID這個(gè)cookie,并且能通過該JSESSIONID的值找到相應(yīng)的session,所以就不需要再重新登錄了。
9.討論幾種極端情況
第一種:當(dāng)項(xiàng)目正常運(yùn)行,我們清空瀏覽器,cookie和session會(huì)發(fā)生什么變化。
因?yàn)榍蹇樟藶g覽器,所以不會(huì)存在JSESSIONID這個(gè)cookie,servlet無法找到對應(yīng)的session,所以他會(huì)新建一個(gè)session,然后在本次請求的響應(yīng)中將sessionId傳入cookie中。
下一次請求,cookie數(shù)組中就帶有JSESSIONID這個(gè)cookie了,servlet就可以找到對應(yīng)的session,沿用即可。
第二種:瀏覽器正常,項(xiàng)目重啟(可停止tomcat來模擬這種情況),cookie和session會(huì)發(fā)生什么變化。
因?yàn)轫?xiàng)目重啟,內(nèi)存中的一切session都消失了,雖然訪問一個(gè)action,請求頭中有JSESSIONID這個(gè)cookie,但是通過它的值(sessionId)并不能找到session(因?yàn)楦緵]有任何session),所以還是得重新創(chuàng)建一個(gè)session,并且這個(gè)session的sessionId跟當(dāng)前cookie數(shù)組中的JSESSIONID的值不一樣,所以它會(huì)將新的sessionId覆蓋掉cookie數(shù)組中原來的JSESSIONID,并且由于此時(shí)的session是嶄新的,所以他不可能有userId這樣的屬性值,所以在攔截的時(shí)候依然會(huì)被截獲,因此也是需要重新登錄的。
有興趣的同學(xué)可以去試驗(yàn)一下。
10.session的時(shí)限
可以通過setMaxInactiveInterval()方法來設(shè)置session的時(shí)限,比如可以設(shè)為半個(gè)小時(shí)。這個(gè)時(shí)間指的是session不活躍開始計(jì)算的時(shí)間。超過這個(gè)時(shí)間,session就失效了。此時(shí)若再getSession(),則會(huì)創(chuàng)建一個(gè)新的session,并且其sessionId為此時(shí)瀏覽器中JSESSIONID的值。
有三種方式來設(shè)置session的時(shí)限:
--通過在web容器中設(shè)置(以tomcat為例),在tomcat-7.0\conf\web.xml中設(shè)置,以下是tomcat7.0中默認(rèn)配置:
<session-config> <session-timeout>30</session-timeout> </session-config>
--通過web項(xiàng)目的web.xml文件來設(shè)置。設(shè)置15分鐘失效。
<session-config> <session-timeout>15</session-timeout> </session-config>
--直接在代碼中設(shè)置
session.setMaxInactiveInterval(30*60);//以秒為單位,即在沒有活動(dòng)30分鐘后,session將失效
上述三種方法的優(yōu)先級:1<2<3.
我們來做個(gè)試驗(yàn),在web.xml中設(shè)置session的過期時(shí)間為1分鐘,然后觀察session和cookie的變化。
第一次訪問:

過了一分鐘后,再次訪問

發(fā)現(xiàn)還是沒變,但馬上再次訪問。

結(jié)合我們之前所說的session和cookie的作用過程來解釋一下:第二次訪問的時(shí)候,因?yàn)檫^了一分鐘,超過了session的過期時(shí)間,所以此時(shí)雖然cookie中還是原來的sessionID(這也是為什么第二次與第一次的請求頭中SessionID相同的原因),但是通過此SessionID是無法再找到那個(gè)已經(jīng)失效的session,所以服務(wù)端必須重新創(chuàng)建一個(gè)session,并且把新的sessionID放到cookie中,覆蓋掉原來舊的。所以當(dāng)我們馬上再次訪問的時(shí)候,這一次就是新的cookie了。
ps:其實(shí)這個(gè)過程跟服務(wù)端暫停服務(wù)的效果是一樣的,只不過服務(wù)端暫停服務(wù)影響的是內(nèi)存中的所有session,而session過期只是影響當(dāng)前過期的這個(gè)session。
pss:cookie過期與session過期類似,只不過是發(fā)生在客戶端,大家可以依照前面講的作用過程試著推導(dǎo)cookie過期會(huì)發(fā)生什么事情。
psss:如果用了redis等內(nèi)存數(shù)據(jù)庫來管理session,那么設(shè)置過期時(shí)間將不起作用。
12.非瀏覽器平臺(tái)使用session
cookie依賴于瀏覽器,session依賴于服務(wù)器。如果項(xiàng)目不在瀏覽器上面運(yùn)行,那么cookie也就無用武之地,但是我們還是想要使用session。不巧的是,session依賴cookie進(jìn)行管理,這時(shí)候要怎么辦呢?
舉個(gè)很常見的場景,我們想要在安卓,或者ios、或者微信小程序等非瀏覽器的項(xiàng)目中使用session。這時(shí)候這些客戶端不會(huì)自動(dòng)幫我們做管理cookie的工作。那么這時(shí)候我們需要自己來做。
前面講到過,servlet底層幫我們自動(dòng)使用cookie來管理session,大體過程是:從cookie中找尋sessionID,根據(jù)sessionID去找session,找到合適的就用,找不到的話就新建一個(gè),并且用新的sessionID覆蓋掉cookie中舊的。
而現(xiàn)在需要明白兩點(diǎn):
(1)我們沒有瀏覽器了,所以不會(huì)在http的請求頭中攜帶cookie信息,servlet后臺(tái)收不到cookie信息,自然找不到JESSIONID,所以他會(huì)在每次請求都創(chuàng)建一個(gè)新的session,這對于服務(wù)端來說,是一筆嚴(yán)重的性能開銷。
(2)因?yàn)闆]有瀏覽器了,servlet在更新完sessionID以后,不會(huì)自動(dòng)執(zhí)行set-cookie操作將新的sessionID去覆蓋舊的cookie中的JESSIONID的值。
根據(jù)以上兩點(diǎn),我我們需要做如下幾件事情。
(1):模擬http請求的時(shí)候在請求頭中帶上cookie,在cookie中塞入從JESSIONID。這樣服務(wù)端就可以取到JESSIONID,從而獲取sessionID,進(jìn)行比對來獲取session;
(2),在響應(yīng)給客戶端的時(shí)候,手動(dòng)調(diào)用set-cookie方法將本次的sessionID放入JESSIONID中,這樣客戶端就可以得到最新的JESSIONID。
(3):然后客戶端需要維護(hù)一個(gè)cookie的靜態(tài)變量(或者用其他方法,總之就是維護(hù)一個(gè)cookie的內(nèi)存變量)。將服務(wù)端響應(yīng)回來的JESSIONID的值存在這個(gè)變量里面。作為下次請求的時(shí)候放入請求頭。
(4):我們同樣可以在服務(wù)端寫一個(gè)攔截器,客戶端的每個(gè)請求都必須先經(jīng)過攔截器,這樣就可以通過session來判斷用戶是否處于登錄狀態(tài)了。這個(gè)過程與在瀏覽器平臺(tái)毫無二致。
下面我們來實(shí)現(xiàn)上面的功能。
由于本人不會(huì)寫安卓和iOS的代碼,所以以一個(gè)客戶端程序來模擬安卓端。
首先,定義一個(gè)靜態(tài)變量用于存儲(chǔ)JESSIONID.初始值為空。
public static String J_SESSIONID="";
接下來我們編寫模擬http請求的類,需要在這個(gè)類中的請求頭中加入cookie,并且在響應(yīng)的時(shí)候得到響應(yīng)頭中的cookie.具體代碼如下。
public static String http4Cookie(String url, String param,String jsessionId) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打開和URL之間的連接
HttpURLConnection connection = (HttpURLConnection) realUrl
.openConnection();
// 設(shè)置通用的請求屬性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.setRequestProperty("Cookie", "JSESSIONID="+jsessionId);//請求頭中加入JessionID
// 建立實(shí)際的連接
connection.connect();
// 獲取所有響應(yīng)頭字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍歷所有的響應(yīng)頭字段,獲取響應(yīng)頭中的JESSIONID信息
for (String key : map.keySet()) {
// System.out.println(key + "--->" + map.get(key));
if("Set-Cookie".equals(key)){
String setCookie=map.get(key).toString();
String newJessionId=setCookie.substring(12,setCookie.lastIndexOf("]"));
J_SESSIONID=newJessionId;// 維護(hù)新的J_SESSIONID
System.out.println(setCookie.substring(12,setCookie.lastIndexOf("]")));
}
}
// 定義 BufferedReader輸入流來讀取URL的響應(yīng)
in = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("發(fā)送GET請求出現(xiàn)異常!" + e);
e.printStackTrace();
}
// 使用finally塊來關(guān)閉輸入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
然后我們在服務(wù)端寫一個(gè)Action讓客戶端來模擬請求。
@ResponseBody
@RequestMapping("httpCookieTest")
public String httpTest(HttpServletRequest req,HttpServletResponse res) {
Cookie[]cookies=req.getCookies();
for(Cookie cookie:cookies){
if(cookie.getName().equals("JSESSIONID"));
System.out.println(cookie.getValue());
}
OutPutMsg.outPutMsg(res, req, "httpCookieTest");
return null;
}
特別注意這里的OutPutMsg,它的代碼如下。
public static void outPutMsg(HttpServletResponse response,HttpServletRequest request,String msg) {
response.setCharacterEncoding("utf-8");
String sessionId = request.getSession().getId();
response.setContentType("text/html; charset=UTF-8");
response.setHeader("Set-Cookie", "JSESSIONID=" + sessionId);
PrintWriter writer = null;
try {
writer = response.getWriter();
writer.print(msg);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null)
writer.close();
}
}
注意到第4和第5行代碼,這兩行代碼往響應(yīng)頭中加入了此時(shí)的sessionId,作為JSESSIONID的值,放入到cookie中。這樣客戶端才能從響應(yīng)頭中獲取最新的JSESSIONID,以更新靜態(tài)變量J_SESSIONID的值,對應(yīng)http4Cookie中的代碼。
然后我們來看看客戶端的主函數(shù)。
public static void main(String args[]){
HttpUtil.http4Cookie("http://192.168.1.185:8080/warrior/httpCookieTest","1=1",J_SESSIONID);
}
這樣以后,其實(shí)這個(gè)過程已經(jīng)跟瀏覽器的cookie運(yùn)作機(jī)制并無二致了。
最后,我們在寫一個(gè)攔截器,對所有客戶端請求進(jìn)行攔截??蛻舳嗣看握埱笾g都率先訪問這個(gè)攔截器。
@ResponseBody
@RequestMapping("otherPlatformIntercept")
public String otherPlatformIntercept(HttpServletRequest req){
HttpSession httpSession=req.getSession();
if(httpSession.getAttribute("userId")!=null){
return "valid";
}
return "Invalid";
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot視圖解析器ViewResolver使用實(shí)例
這篇文章主要介紹了Springboot視圖解析器ViewResolver使用實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
SpringBoot實(shí)現(xiàn)EMQ設(shè)備的上下線告警
EMQX?的上下線系統(tǒng)消息通知功能在客戶端連接成功或者客戶端斷開連接,需要實(shí)現(xiàn)設(shè)備的上下線狀態(tài)監(jiān)控,所以本文給大家介紹了如何通過SpringBoot實(shí)現(xiàn)EMQ設(shè)備的上下線告警,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-10-10
K8S環(huán)境下如何驗(yàn)證RocketMQ擴(kuò)縮容
文章主要內(nèi)容驗(yàn)證了K8S環(huán)境下RocketMQ的擴(kuò)縮容特性,包括序號變化、命名規(guī)則以及節(jié)點(diǎn)重建后序號保持不變,StatefulSet確保Pod序號在重建后保持穩(wěn)定,而Deployment創(chuàng)建的Pod名稱是隨機(jī)的2025-01-01
SpringMVC實(shí)現(xiàn)返回響應(yīng)的項(xiàng)目實(shí)踐
本文主要介紹了SpringMVC實(shí)現(xiàn)返回響應(yīng)的項(xiàng)目實(shí)踐,包含返回靜態(tài)頁面,返回?cái)?shù)據(jù),返回html片段等實(shí)例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
Java實(shí)現(xiàn)寵物商店管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)寵物商店管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
Java中資源加載的方法及Spring的ResourceLoader應(yīng)用小結(jié)
在Java開發(fā)中,資源加載是一個(gè)基礎(chǔ)而重要的操作,這篇文章主要介紹了深入理解Java中資源加載的方法及Spring的ResourceLoader應(yīng)用,本文通過實(shí)例代碼演示了通過ClassLoader和Class獲取資源的內(nèi)容,以及使用Spring的ResourceLoader加載多個(gè)資源的過程,需要的朋友可以參考下2024-01-01

