Java匹馬行天下之JavaWeb核心技術——JSP(續一)
序:昨天完成了Java匹馬行天下之JavaWeb核心技術——JSP的一部分,我的初心是想查漏補缺,把之前沒學過的東西補上,卻沒想到部落格釋出後反響這麼大,部落格推薦數、閱讀數還有評論數創我的歷史新高,有博友評論說JSP都過時了,為什麼還有這麼多人推薦。我僅代表個人說一下我的看法,我是一名大二的學生,我覺得對於像我這樣剛入門的菜鳥來說沒有太多的選擇,不論選什麼都逃不過學習基礎知識,我需要做的是保持理智,不盲目追“新”,技術更新確實很快,而我這個菜鳥連過時的是什麼都不知道,我至少得了解JSP為什麼過時了吧,通過過時的JSP更新我的知識體系,我覺得這是一種態度。就像我們學了SpringBoot,不也是先學Spring,MyBitas,SpringMvc過來的嗎,別忘了,新的知識都是從過時的知識演變來的,不是還有溫故而知新嗎,何況我是初學者,連溫故都談不上,我認為不是什麼新就學什麼,而是需要什麼學什麼,寫專案還得看甲方需求呢,僅代表個人觀點,我還是菜鳥,在軟體這條路上正在摸爬滾打摸索之中,虛心聽取博友提供的好方法,至於諷刺,我是菜鳥,我是菜鳥,我是菜鳥,重要的事情說三遍,尊重是互相的,謝謝!
十二、JSP表單處理
我們在瀏覽網頁的時候,經常需要向伺服器提交資訊,並讓後臺程式處理。瀏覽器中使用 GET 和 POST 方法向伺服器提交資料。
GET 方法
GET方法將請求的編碼資訊新增在網址後面,網址與編碼資訊通過"?"號分隔。如下所示:
http://www.runoob.com/hello?key1=value1&key2=value2
GET方法是瀏覽器預設傳遞引數的方法,一些敏感資訊,如密碼等建議不使用GET方法。
用get時,傳輸資料的大小有限制 (注意不是引數的個數有限制),最大為1024位元組。
POST 方法
一些敏感資訊,如密碼等我們可以通過POST方法傳遞,POST提交資料是隱式的。
POST提交資料是不可見的,GET是通過在url裡面傳遞的(可以看一下你瀏覽器的位址列)。
JSP使用getParameter()來獲得傳遞的引數,getInputStream()方法用來處理客戶端的二進位制資料流的請求。
JSP 讀取表單資料
- getParameter(): 使用 request.getParameter() 方法來獲取表單引數的值。
- getParameterValues(): 獲得如checkbox類(名字相同,但值有多個)的資料。 接收陣列變數 ,如checkbox型別
- getParameterNames():該方法可以取得所有變數的名稱,該方法返回一個 Enumeration。
- getInputStream():呼叫此方法來讀取來自客戶端的二進位制資料流。
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <title>表單資訊</title> </head> <body> <form action="Demo1.jsp" method="post"> <input type="text" name="name"/><br> <input type="text" name="url"/><br> <input type="checkbox" name="mao" checked="checked"/>貓<br> <input type="checkbox" name="gou"/>狗<br> <input type="checkbox" name="ji" checked="checked"/>雞<br> <input type="checkbox" name="ya"/>鴨<br> <input type="submit" value="提交"> </form> </body> </html>
<%@ page import="java.util.Enumeration" %> <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JSP</title> </head> <body> <h1>讀取引數資訊</h1> <table align="center" border="1" width="100%"> <tr bgcolor="#f0f8ff"> <th>引數名</th> <th>對應值</th> </tr> <% Enumeration<String> parameterNames = request.getParameterNames(); request.setCharacterEncoding("utf-8"); while (parameterNames.hasMoreElements()){ String name = parameterNames.nextElement(); out.println("<tr><td>"+name+"</td>\n"); String url = request.getParameter(name); out.println("<td>"+url+"</td></tr>\n"); } %> </table> <% %> </body> </html>
十三、四大域物件:實際開發如何用?
PageContext:pageConext 存放的資料僅在當前頁面有效。開發時使用較少。當前頁面存放資料用表單標籤中的 <input type="hidden" />,且該存值方式使用者看不到。
ServletRequest: request 存放的資料在一次請求(轉發:可以傳資料)內有效。使用非常多。
HttpSession: session 存放的資料在一次會話(多次請求)中有效。使用的比較多。例如:存放使用者的登入資訊、購物車功能。
ServletContext: application 存放的資料在整個應用範圍內都有效。因為範圍太大,應儘量少用。用於統計線上人數。
十四、會話跟蹤
-
會話概述
1、什麼是會話?如同打電話。
會話可簡單理解為:使用者開一個瀏覽器,點選多個超連結,訪問伺服器多個web資源,然後關閉瀏覽器,整個過程稱之為一個會話。
2、會話過程要解決的問題是什麼?保持各個客戶端自己的資料。
每個使用者在使用瀏覽器與伺服器進行會話的過程中,不可避免各自會產生一些資料,程式要想辦法為每個使用者儲存這些資料。
例如:使用者點選超連結通過一個servlet購買了一個商品,程式應該想辦法儲存使用者購買的商品,以便於使用者點結帳servlet時,結帳servlet可以得到使用者購買的商品為使用者結帳。
思考:使用者購買的商品儲存在request或servletContext中行不行?答:不行。
儲存會話資料的兩種技術:
Cookie:是客戶端技術,程式把每個使用者的資料以cookie的形式寫給使用者各自的瀏覽器。
當用戶使用瀏覽器再去訪問伺服器中的web資源時,就會帶著各自的資料去。
這樣,web資源處理的就是使用者各自的資料了。
HttpSession:Session是伺服器端技術,利用這個技術,伺服器在執行時可以為每一個使用者的瀏覽器建立一個其獨享的HttpSession物件,
由於session為使用者瀏覽器獨享,所以使用者在訪問伺服器的web資源時,可以把各自的資料放在各自的session中,
當用戶再去訪問伺服器中的其它web資源時,其它web資源再從使用者各自的session中取出資料為使用者服務。
-
http協議的無狀態性
無狀態是指,當瀏覽器傳送請求給伺服器時,伺服器響應客戶端請求。但是當同一個瀏覽器再次傳送請求給伺服器時,伺服器並不知道它就是剛才那個瀏覽器。簡單來說,就是伺服器不會去記得你,所以就是無狀態協議。
-
JSP Cookie 處理
Cookie是儲存在客戶機的文字檔案,它們儲存了大量軌跡資訊。在servlet技術基礎上,JSP顯然能夠提供對HTTP cookie的支援。
通常有三個步驟來識別回頭客:
- 伺服器指令碼傳送一系列cookie至瀏覽器。比如名字,年齡,ID號碼等等。
- 瀏覽器在本地機中儲存這些資訊,以備不時之需。
- 當下一次瀏覽器傳送任何請求至伺服器時,它會同時將這些cookie資訊傳送給伺服器,然後伺服器使用這些資訊來識別使用者或者幹些其它事情。
JSP Cookie 處理需要對中文進行編碼與解碼,方法如下:
String str = java.net.URLEncoder.encode("中文","UTF-8"); //編碼 String str = java.net.URLDecoder.decode("編碼後的字串","UTF-8"); // 解碼
-
Servlet Cookie 方法
-
使用JSP設定Cookie
使用JSP設定cookie包含三個步驟:
(1)建立一個Cookie物件: 呼叫Cookie的建構函式,使用一個cookie名稱和值做引數,它們都是字串。
Cookie cookie = new Cookie("key","value");
請務必牢記,名稱和值中都不能包含空格或者如下的字元:
[ ] ( ) = , " / ? @ : ;
(2) 設定有效期:呼叫setMaxAge()函式表明cookie在多長時間(以秒為單位)內有效。下面的操作將有效期設為了24小時。
cookie.setMaxAge(60*60*24);
(3) 將cookie傳送至HTTP響應頭中:呼叫response.addCookie()函式來向HTTP響應頭中新增cookie。
response.addCookie(cookie);
-
例項說明
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>表單提交</title> </head> <body> <form action="CookieDemo.jsp" method=GET> 站點名: <input type="text" name="name"> <br /> 網址: <input type="text" name="url" /> <input type="submit" value="提交" /> </form> </body> </html>
<%@ page import="java.net.URLEncoder" %> <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> <% // 編碼,解決中文亂碼 String str = URLEncoder.encode(request.getParameter("name"),"utf-8"); // 設定 name 和 url cookie Cookie name = new Cookie("name", str); Cookie url = new Cookie("url", request.getParameter("url")); // 設定cookie過期時間為24小時。 name.setMaxAge(60*60*24); url.setMaxAge(60*60*24); // 在響應頭部新增cookie response.addCookie( name ); response.addCookie( url ); %> <html> <head> <title>設定 Cookie</title> </head> <body> <h1>設定 Cookie</h1> <ul> <li><p><b>網站名:</b> <%= request.getParameter("name")%> </p></li> <li><p><b>網址:</b> <%= request.getParameter("url")%> </p></li> </ul> </body> </html>
-
使用 JSP 讀取 Cookie
想要讀取cookie,您就需要呼叫request.getCookies()方法來獲得一個javax.servlet.http.Cookie物件的陣列,然後遍歷這個陣列,使用getName()方法和getValue()方法來獲取每一個cookie的名稱和值。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.net.*" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>獲取 Cookie</title> </head> <body> <% Cookie cookie = null; Cookie[] cookies = null; // 獲取cookies的資料,是一個數組 cookies = request.getCookies(); if( cookies != null ){ out.println("<h2> 查詢 Cookie 名與值</h2>"); for (int i = 0; i < cookies.length; i++){ cookie = cookies[i]; out.print("引數名 : " + cookie.getName()); out.print("<br>"); out.print("引數值: " + URLDecoder.decode(cookie.getValue(), "utf-8") +" <br>"); out.print("------------------------------------<br>"); } }else{ out.println("<h2>沒有發現 Cookie</h2>"); } %> </body> </html>
-
使用JSP刪除Cookie
刪除cookie非常簡單。如果您想要刪除一個cookie,按照下面給的步驟來做就行了:
- 獲取一個已經存在的cookie然後儲存在Cookie物件中。
- 將cookie的有效期設定為0。
- 將這個cookie重新新增進響應頭中。
-
例項演示
下面的程式刪除一個名為"name"的cookie,當您第二次執行CookieDemo2.jsp時,name 將會為 null。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.net.*" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>獲取 Cookie</title> </head> <body> <% Cookie cookie = null; Cookie[] cookies = null; // 獲取當前域名下的cookies,是一個數組 cookies = request.getCookies(); if( cookies != null ){ out.println("<h2> 查詢 Cookie 名與值</h2>"); for (int i = 0; i < cookies.length; i++){ cookie = cookies[i]; if((cookie.getName( )).compareTo("name") == 0 ){ cookie.setMaxAge(0); response.addCookie(cookie); out.print("刪除 Cookie: " + cookie.getName( ) + "<br/>"); } out.print("引數名 : " + cookie.getName()); out.print("<br>"); out.print("引數值: " + URLDecoder.decode(cookie.getValue(), "utf-8") +" <br>"); out.print("------------------------------------<br>"); } }else{ out.println("<h2>沒有發現 Cookie</h2>"); } %> </body> </html>
-
圖解分析
-
Session
-
HttpSession概述
HttpSession是有JavaWeb提供的,用來會話跟蹤的類,session是伺服器物件,儲存在伺服器端;
HttpSession是Servlet三大域物件之一(request、session、application),所以它也有setAttribute()、getAttribute()、removeAttribute()方法;
HttpSession底層依賴Cookie,或是URL重寫。
-
HttpSession的作用
- 會話範圍:會話範圍是某個使用者從首次訪問伺服器開始,到該使用者關閉瀏覽器結束;
會話:一個使用者對伺服器的多次連貫性請求,所謂連貫性請求,就是該使用者多次請求中間沒有關閉瀏覽器。
- 伺服器會為每個客戶端建立一個session物件,session就好比客戶在伺服器端的賬戶,它們被伺服器儲存到一個Map中,這個Map被稱為session快取。
Servlet中得到session物件:HttpSession session = request.getSession();
JSP中得到session物件:session是jsp內建物件之下,不用建立就可以直接使用。
-
session域相關方法
void setAttribute(String name,Object val); Object getAttribute(String name); void removeAttribute(String name);
-
session儲存使用者登入資訊
- 案例相關頁面和Servlet:
login.jsp 登入頁面
LoginSuccess.jsp 只有登入成功才能訪問的頁面
LoginServlet:校驗使用者是否登入成功
- 各頁面和Servlet內容:
login.jsp 提供登入表單,提交表單請求LoginServlet
LoginServlet 獲取請求引數,校驗使用者是否登入成功
失敗:儲存錯誤資訊到request域,轉發到login.jsp,在login.jsp中顯示request域中的錯誤資訊;
成功:儲存使用者資訊到session域中,重定向到LoginSuccess.jsp頁面,顯示session域中的使用者資訊。
LoginSuccess.jsp 從session域獲取使用者資訊,如果不存在,顯示“您還沒有登入”,存在則顯示使用者資訊;
只要使用者沒有關閉瀏覽器,session就一直存在,那麼儲存在session中的使用者資訊也就一起存在,那麼使用者訪問LoginSuccess.jsp就會通過
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html> <head> <title>登入頁面</title> </head> <body> <% //獲取cookie的值 String name = ""; String pwd = ""; Cookie[] cs = request.getCookies(); if(cs!=null){ for(Cookie c : cs){ if("username".equals(c.getName())){ name = c.getValue(); } if("pwd".equals(c.getName())){ pwd = c.getValue(); } } } %> <% //獲取request資訊 String message=""; String mess = (String)request.getAttribute("message"); if(mess!=null){ message = mess; } %> <h1>使用者登入</h1> <span color="red"><%=message %></span> <form action="/LoginServlet" method="post"> <p> 賬號:<input type="text" name="username" value="<%=name %>" /> </p> <p> 密碼:<input type="password" name="pwd" value="<%=pwd %>" /> </p> <p> <input type="submit" value="登入"> </p> </form> </body> </html>
LoginServlet.java
package com.demo.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //設定請求的字元編碼 request.setCharacterEncoding("utf-8"); //接收客戶端請求 String username = request.getParameter("username"); String pwd = request.getParameter("pwd"); //判斷是否登入成功 if("admin".equals(username) && "1234".equals(pwd)){ //登入成功,把資訊儲存到cookie中 Cookie c1 = new Cookie("username",username); Cookie c2 = new Cookie("pwd",pwd); c1.setMaxAge(60*60*24); c2.setMaxAge(60*60*24); response.addCookie(c1); response.addCookie(c2); //登入成功,儲存使用者名稱到session中,並重定向到LoginSuccess.jsp HttpSession session = request.getSession(); session.setAttribute("username", username); response.sendRedirect("/LoginSuccess.jsp"); }else{ //轉發給客戶端“登入失敗” request.setAttribute("message", "使用者資訊錯誤,請重新登入"); request.getRequestDispatcher("/login.jsp").forward(request, response); } } }
LoginSuccess.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html> <head> <title>登入成功</title> </head> <body> <% //獲取session資訊 String name = (String)session.getAttribute("username"); if(name==null){ //session不存在,轉發到登入頁面,並提示資訊 request.setAttribute("message", "您還沒有登入,不能訪問頁面"); request.getRequestDispatcher("/login.jsp").forward(request, response); //重定向到login.jsp,不會顯示request提示的資訊 //response.sendRedirect("/login/login.jsp"); return; } %> <h1>登入成功</h1> 你好<%=name %>,歡迎登入! </body> </html>
-
隱藏表單域
一個網路伺服器可以傳送一個隱藏的HTML表單域和一個唯一的session ID,就像下面這樣:
<input type="hidden" name="sessionid" value="12345">
這個條目意味著,當表單被提交時,指定的名稱和值將會自動包含在GET或POST資料中。每當瀏覽器傳送一個請求,session_id的值就可以用來儲存不同瀏覽器的軌跡。
這種方式可能是一種有效的方式,但點選<A HREF>標籤中的超連結時不會產生表單提交事件,因此隱藏表單域也不支援通用會話跟蹤。
-
重寫URL
您可以在每個URL後面新增一些額外的資料來區分會話,伺服器能夠根據這些資料來關聯session識別符號。
舉例來說,http://w3cschool.cc/file.htm;sessionid=12345, session識別符號為sessionid=12345,伺服器可以用這個資料來識別客戶端。
相比而言,重寫URL是更好的方式來,就算瀏覽器不支援cookies也能工作,但缺點是您必須為每個URL動態指定session ID,就算這是個簡單的HTML頁面。
- session依賴Cookie,目的是讓客戶端發出請求時歸還sessionID,這樣才能找到對應的session;
- 如果客戶端禁用了Cookie,那麼就無法得到sessionID,那麼session也就無用了;
- 也可以使用URL重寫來替代Cookie
- 讓網站的所有超連結、表單中都新增一個特殊的請求引數,即sessionID;
- 這樣伺服器可以通過獲取請求引數得到sessionID,從而找到session物件;
- response.encodeURL(String url)該方法會對url進行智慧的重寫,當請求中沒有歸還session這個Cookie,那麼該方法會重寫URL,否則不重寫,當然url必須是指向本站的url。
-
session物件
除了以上幾種方法外,JSP利用servlet提供的HttpSession介面來識別一個使用者,儲存這個使用者的所有訪問資訊。
預設情況下,JSP允許會話跟蹤,一個新的HttpSession物件將會自動地為新的客戶端例項化。禁止會話跟蹤需要顯式地關掉它,通過將page指令中session屬性值設為false來實現,就像下面這樣:
<%@ page session="false" %>
JSP引擎將隱含的session物件暴露給開發者。由於提供了session物件,開發者就可以方便地儲存或檢索資料。
下表列出了session物件的一些重要方法:
-
Session與Cookie的對比
-
HttpSession原理
伺服器不會馬上給你建立session,在第一次獲取session時,即reques.getSession()方法執行時,才會建立session。
獲取Cookie中的JSESSIONID:
- 如果sessionID不存在,建立session,把session儲存起來,把新建立的sessionID儲存到Cookie中;
- 如果sessionID存在,建立sessionID查詢session物件,如果沒有查詢到,建立session,把session儲存起來,把新建立的sessionID儲存到Cookie中;
- 如果sessionID存在,通過sessionID查詢到了session物件,那麼就不會再建立session物件了;
- 如果建立新的session,瀏覽器會得到一個包含了sessionID的Cookie,這個Cookie的生命為-1,即只在瀏覽器記憶體中存在,如果不關閉瀏覽器,那麼Cookie就會一直存在;
- 下次請求時,再執行request.getSession()方法時,因為可以通過Cookie中的sessionID找到session物件,所以與上一次請求使用的是同一個session物件。
- request.getSession(false):如果Cookie不存在,session也不存在,那麼返回NULL,而不會建立session物件;
- request.getSession(true)/request.getSession():兩個方法一樣,當session物件不存在時,建立session物件
- String getId() 獲取sessionID;
- int getMaxInactiveInterval() 獲取session最大的不活動時間(秒),預設為30分鐘,當session在30分鐘內沒有使用,那麼Tomcat就會在session池中移除;
- void invalidate() 讓session失效,呼叫這個方法會讓session失效,當session失效後,客戶端再次請求,伺服器會給客戶端一個新的session;
- boolean isNew() 檢視session是否為新的,判斷是新建立的,還是從Cookie獲取的;
(未完待續)
此篇是我在學習過程中參考菜鳥教程以及筆記和別人部落格(黑澤君)完成
Java匹馬行天下依舊在更新中,歡迎大家關注,感覺可以的可以點選一下推薦,若如有誤,感謝指正,謝