Servlet傳遞資料方式
基本概述
Servlet傳遞資料的方式有很多,這裡提供五種方式:
1、靜态變量
2、HttpServletResponse的sendRedirect()方法
3、HttpServletRequest的getRequestDispatch()方法
4、HttpServletRequest的getSession()方法
5、HttpServletRequest的setAttribute()方法
靜态變量
通過建立一個資料類來進行傳遞。
案例:
public class MyData{
public static String data; //通過使用該類來實作資料傳遞
}
接收到用戶端請求後,可以通過 HttpServletResponse 對象直接進行響應,響應時需要擷取輸出流,
有兩種形式
getWriter()擷取字元流(隻能響應回字元);
getOutputStream()擷取位元組流(能響應一切資料)。
響應回的資料到用戶端被浏覽器解析。
注意:兩者不能同時使用。
HttpServletResponse的sendRedirect()方法
sendRedirect()方法是讓浏覽器重定向到另一個連結。其内部原理是設定狀态碼為303,并設定相應的Location響應頭。
基本文法:
response.sendRedirect("/Web應用名/資源名?uname="+username+"&pwd="+password);
response.sendRedirect(“servlet的位址?參數名=參數值&參數名=參數值...”);
參照值是String , 參數名應當使用 字母組合
在接受資料的Servlet中:
String 參數=request.getParameter(“參數名”);
基本原理圖

PS:使用重定向不能使用PrintWrite,ServletOutputStream這樣的流。因為重定向已經将消息傳回給浏覽器,其資料流也就沒必要使用了。
HttpServletRequest的getRequestDispatch()方法
getRequestDispatch()方法是使WEB伺服器從目前Servlet轉發到目前應用下的另一個Servlet。
基本文法:
request.getRequestDispatcher(資源位址).forward(request,response);
資源位址:不需要項目名。因為它隻能在WEB伺服器内部轉發。
基本原理圖
PS:getRequestDispatcher()請求轉發可以一直轉發下去,隻要最終會處理并給伺服器相應内容就行了。而且請求轉發不會改變浏覽器的URL,sendRedirect()會改變URL。
注意事項:
1、使用forward不能轉發到該WEB應用外的URL
2、因為forward發生在文本伺服器内,是以Servlet1、Servlet2等等,隻要一直轉發,使用的都是相同的request和response
示例:
@SuppressWarnings("serial")
public class Servlet02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet02...");
// 設定響應類型
resp.setContentType("text/html;charset=UTF-8");
// getWriter()擷取字元流(隻能響應回字元);
//PrintWriter writer = resp.getWriter();
//writer.write("<h4>Hello Servlet</h4>");
//writer.close();
// getOutputStream()擷取位元組流(能響應一切資料)。
//OutputStream outputStream = resp.getOutputStream();
//outputStream.write("<h4>Hello MyServlet</h4>".getBytes());
//outputStream.close()
String form = "<form action='ser02' method='get'>"
+ "<div class='form-group'><label for='uname'>名稱</label>"
+ " <input type='text' class='form-control' name='uname' placeholder='請輸入名稱'>"
+ "</div> <div class='form-group'> <label for='upwd'>密碼</label> "
+ " <input type='password' class='form-control' name='upwd' placeholder='請輸入密碼'> </div>"
+ " <button type='submit' >送出</button> </form>";//拼接表格
resp.getWriter().write(form);
resp.getWriter().close();
}
}
HttpServletRequest的getSession()方法
getSession()方法會擷取一個會話,這個内容會在另一篇部落格會話技術中詳細說明。
基本文法:
1、放入session:request.getSession.setAttribute("loginUser",username);
2、取出session:request.getSession.getAttribute("loginUser");
PS:該方法可以傳遞對象
案例:
放入:
User user= new User();
user.setName(“zs”);
user.setPassWord(“123”);
request.getSession.setAttribute("userObj",userObj);
取出:
User user=(User)request.getSession.getAttribute(“userObj”);
HttpServletRequest的setAttribute()方法
setAttribute()方法可以設定一個鍵值對,該鍵值對在該request的有效期内都可以使用。相應的還有removeAttribute()登出鍵值對的方法。該方法經常和getRequestDispatch()一起使用。
基本文法:
setAttribute(name, value);
PS:request的Attribute在一次請求中有效。一次請求:沒有将響應消息傳回給浏覽器就視為一次請求。
比較sendRedirect()和forward(request,response)
1、sendRedirect()重定向,forward()轉發
2、實際發生的位置不一樣
sendRedirect 發生在浏覽器
forward 發生在web伺服器
3、使用用法不一樣
request.getRequestDispatcher(“/資源URI”).forward(request,response)
response.sendRedirect(“/web應用/資源URI”);
4、能夠去URL範圍不一樣
sendRedirect可以去任意URL
forward 隻能去目前的WEB應用的資源
亂碼解決
如果響應的内容中含有中文,則有可能出現亂碼。
這是因為伺服器響應的資料也會經過網絡傳輸,伺服器端有一種編碼方式,在用戶端也存在一種編碼方式,當兩端使用的編碼方式不同時則出現亂碼。
getWriter()的字元亂碼
對于 getWriter()擷取到的字元流,響應中文必定出亂碼,由于伺服器端在進行編碼時預設會使用 ISO-8859-1 格式的編碼,該編碼方式并不支援中文。
是以要解決該種亂碼隻能在伺服器端告知伺服器使用一種能夠支援中文的編碼格式,
比如我們通常用的“UTF-8” resp.setCharacterEncoding("UTF-8");,
此時還隻完成了一半的工作,要保證資料正确顯示,還需要指定用戶端的解碼方式
resp.setHeader("content-type", "text/html;charset=UTF-8");,
和伺服器一緻。兩端指定編碼後,亂碼就解決了。
一句話:保證發送端和接收端的編碼一緻
getOutputStream()位元組亂碼
對于 getOutputStream()方式擷取到的位元組流,響應中文時,由于本身就是傳輸的位元組, 是以此時可能出現亂碼,也可能正确顯示,這就看人品了^_^。
當伺服器端給的位元組恰好和用戶端使用的編碼方式一緻時則文本正确顯示,否則出現亂碼。
無論如何我們都應該準确掌握伺服器和用戶端使用的是那種編碼格式,以確定資料正确顯示。指定用戶端和伺服器使用的編碼方式一緻即可 。
示例:
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet03...");
/* 設定客服端和服務端的編碼一緻,并支援中文*/
// 設定服務端的編碼
//resp.setCharacterEncoding("UTF-8");
// 設定用戶端的編碼
//resp.setHeader("content-type", "text/html;charset=UTF-8");
// 使用一句代碼代替上面兩句
resp.setContentType("text/html;charset=UTF-8"); // 設定響應類型及編碼格式
// getWriter()擷取字元流(隻能響應回字元);
/*PrintWriter writer = resp.getWriter();
writer.write("<h4>你好</h4>");
writer.close();*/
// getOutputStream()擷取位元組流(能響應一切資料)。
OutputStream outputStream = resp.getOutputStream();
outputStream.write("<h4>你好</h4>".getBytes());
outputStream.close();
}
}
總結:
亂碼的原因:
1、用戶端和服務端編碼不一緻
2、編碼不支援中文
解決方案:
保證用戶端和服務端編碼一緻且支援中文
response.setContentType("text/html;charset=UTF-8");
三、請求轉發和重定向
請求轉發:
request.getRequestDispatcher(URL位址).forward(request, response)
處理流程:
用戶端發送請求,Servlet做出業務邏輯處理。
Servlet調用forword()方法,伺服器Servlet把目标資源傳回給用戶端浏覽器。
請求轉發
2)重定向:
response.sendRedirect(URL位址)
處理流程:
用戶端發送請求,Servlet做出業務邏輯處理。
Servlet調用response.sendReadirect()方法,把要通路的目标資源作為response響應頭資訊發給用戶端浏覽器。
用戶端浏覽器重新通路伺服器資源xxx.jsp,伺服器再次對用戶端浏覽器做出響應。
重定向
以上兩種情況,你都需要考慮Servlet處理完後,資料如何在jsp頁面上呈現。圖例是請求、響應的流程,沒有标明資料如何處理、展現。
示例:
@SuppressWarnings("serial")
public class Servlet06 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet06...");
// 接收參數
String uname = req.getParameter("uname");
System.out.println("Servlet06 uname: " + uname);
// 擷取域對象的值
System.out.println(req.getAttribute("num"));
}
四、轉發和重定向的路徑問題
1)使用相對路徑在重定向和轉發中沒有差別
2)重定向和請求轉發使用絕對路徑時,根/路徑代表了不同含義
重定向response.sendRedirect("xxx")是伺服器向用戶端發送一個請求頭資訊,由用戶端再請求一次伺服器。/指的Tomcat的根目錄,寫絕對路徑應該寫成"/目前Web程式根名稱/資源名" 。如"/WebModule/login.jsp","/bbs/servlet/LoginServlet"
轉發是在伺服器内部進行的,寫絕對路徑/開頭指的是目前的Web應用程式。絕對路徑寫法就是"/login.jsp"或"/servlet/LoginServlet"。
總結:以上要注意是區分是從伺服器外的請求,還在是内部轉發,從伺服器外的請求,從Tomcat根寫起(就是要包括目前Web的根);是伺服器内部的轉發,很簡單了,因為在目前伺服器内,/寫起指的就是目前Web的根目錄。
示例:
@SuppressWarnings("serial")
public class Servlet07 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet07...");
// 請求轉發 req.getRequestDispatcher("index.html").forward(req, resp); //OK
req.getRequestDispatcher("/index.html").forward(req, resp); // OK
req.getRequestDispatcher("s03/index.html").forward(req, resp); // No HTTP Status 404 - /s03/s03/index.html req.getRequestDispatcher("/s03/index.html").forward(req, resp); // No HTTP Status 404 - /s03/s03/index.html
req.getRequestDispatcher("http://localhost:8080/s03/index.html").forward(req, resp); // No HTTP Status 404 - /s03/http://localhost:8080/s03/index.html
req.getRequestDispatcher("http://www.shsxt.com").forward(req, resp); // No HTTP Status 404 - /s03/http://www.shsxt.com
// 重定向
// resp.sendRedirect("index.html"); // OK
// resp.sendRedirect("/index.html"); // No http://localhost:8080/index.html
// resp.sendRedirect("s03/index.html"); // No HTTP Status 404 - /s03/s03/index.html
// resp.sendRedirect("/s03/index.html"); OK
// resp.sendRedirect("http://localhost:8080/s03/index.html");
resp.sendRedirect("http://www.shsxt.com");
}
}
五、轉發和重定向的差別
request.getRequestDispatcher()是容器中控制權的轉向,在用戶端浏覽器位址欄中不會顯示出轉向後的位址;伺服器内部轉發,整個過程處于同一個請求當中。
response.sendRedirect()則是完全的跳轉,浏覽器将會得到跳轉的位址,并重新發送請求連結。這樣,從浏覽器的位址欄中可以看到跳轉後的連結位址。不在同一個請求。重定向,實際上用戶端會向伺服器端發送兩個請求。
是以轉發中資料的存取可以用request作用域:request.setAttribute(), request.getAttribute(),重定向是取不到request中的資料的。隻能用session。
forward()更加高效,在可以滿足需要時,盡量使用RequestDispatcher.forward()方法。(思考一下為什麼?)
RequestDispatcher是通過調用HttpServletRequest對象的getRequestDispatcher()方法得到的,是屬于請求對象的方法。
sendRedirect()是HttpServletResponse對象的方法,即響應對象的方法,既然調用了響應對象的方法,那就表明整個請求過程已經結束了,伺服器開始向用戶端傳回執行的結果。
重定向可以跨域通路,而轉發是在web伺服器内部進行的,不能跨域通路。
六. 請求轉發和重定向兩種跳轉方式的差別
請求轉發:request.getRequsetDispatcher().forward(requset,response);
重定向:response.sendRedirect(),
1)轉發作用于伺服器端,是在伺服器内部進行轉發。重定向作用于用戶端,相當于用戶端重新發送一次新的請求。
2)轉發後位址欄不會改變。重定向後位址欄改變。
3)轉發後資源能擷取到請求中的資料。重定向後的資源不能獲得原請求中的資料。
4)轉發隻能在本應用内部資源之間進行。重定向可以跳轉到任何網絡資源。
5)轉發可以通路受保護資源(WEB-INF裡的資源)。重定向不能定位到受保護資源。
request.getRequsetDispatcher().forward(requset,response);
請求轉發
1、隻有一次請求,request作用域中的資料可以共享
2、浏覽器位址欄不發生改變
3、服務端行為
4、跳轉的絕對位址可以定位到站點名後
隻能請求轉發到目前項目下的資源
重定向的差別
1、有兩次請求,request作用域中的資料不可以共享
2、浏覽器位址欄發生改變
3、用戶端行為
4、跳轉的絕對位址可以定位到http://後面
重定向可以定位到任意資源
請求轉發和重定向不能同時使用
路徑問題
相對路徑
路徑的前面不要加任何符号,一般情況下代表的是: "http://localhost:8080/站點名/"
絕對路徑
1、以http://開頭的,完整的絕對路徑,可以跨域,可以通路任何資源
2、以"/"開頭,隻能通路目前項目下的資源
請求轉發和重定向的"/"代表的含義:
1、請求轉發(服務端跳轉):http://localhost:8080/站點名/
2、重定向(用戶端跳轉):"http://localhost:8080/"
用戶端跳轉:
表單送出、超連結跳轉、位址欄直接收入、重定向
服務端跳轉:
請求轉發
七. servlet四大域對象
pageContext
pageContext作用域為page(頁面執行期)。
request
request是表示一個請求,隻要發出一個請求就會建立一個request,它的作用域僅在目前請求中有效。
用處:常用語伺服器間同一請求不同頁面之間的參數傳遞,常用語表單的控件值傳遞。
方法:request.setAttribute(); reuqest.getAttribute();
request.removeAttribute(); request.getParameter();
session
伺服器會為每一個會話建立一個Session對象,是以Session中的資料可供目前會話中所有Servlet共享。
用處:常用于web開發中的登入驗證界面(當使用者登陸成功後浏覽器配置設定其中一個Session鍵值對)。
方法:session.setAttribute(); session.getAttribute();
session.removeAttribute();
擷取Session對象:
HttpSession session = request.getSession();
Application(ServletContext上下文)
作用範圍:所有的使用者都可以取得此資訊,此資訊在整個伺服器端被保留。Application屬性範圍值隻要設定一次,則所有的網頁視窗都可以取得資料。ServletContext在伺服器啟動時建立,在伺服器關閉時銷毀,一個JavaWeb應用隻建立一個ServletContext對象。
方法:ServletContext application = this.getServletContext();
application.setAttribute(); application.getAttribute();
application.removeAttribute();
Servlet作用域
例如,我們通路index.jsp的時候,分别對pageContext、request、session、application四個作用域進行累加。 計算完成後就從index.jsp執行forward轉發到test.jsp,在test.jsp裡再進行一次累加,然後顯示出這四個整數來。
從結果來看:
①page裡的變量沒法從index.jsp傳遞到test.jsp,隻要頁面跳轉了,它們就不見了。
②request裡的變量可以跨越forward前後兩頁。但是隻要重新整理頁面,它們就重新計算了。
③session和application的變量一直在累加,開始還看不出差別,隻要關閉浏覽器,再次重新開機浏覽器通路這個頁面,session裡的變量就重新計算了。application裡的變量一直在累加,除非你重新開機Tomcat,否則它會一直變大。
作用域規定的是變量的有效期限
①如果把變量放到pageContext裡,就說明它的作用域是page,它的有效範圍隻在目前JSP頁面裡。從把變量放到pageContext開始,知道JSP頁面跳轉都可以使用。
②如果把變量放到request裡,就說明它的作用域是request,它的有效範圍是目前請求周期。 所謂請求周期:就是從Http請求發起,到伺服器處理結束,傳回響應的整個過程。在這個過程中可能使用forward的方式跳轉了多個JSP頁面,在這些頁面裡,你都可以使用這個變量。
③如果把這個變量放到session裡,就說明它的作用域是session,它的有效範圍是目前會話。 所謂目前會話:就是指從使用者打開浏覽器開始,知道使用者關閉浏覽器這中間的過程,這個過程可能包含多個請求響應。 也就是說,隻要使用者不關閉浏覽器,伺服器就有辦法知道這些請求是一個人發起的,整個過程被稱為一個會話,而放到會話中的變量,就可以在目前會話的所有請求裡使用。
④如果把變量放到application裡,就說明它的作用域是application,它的有效範圍是整個應用。 所謂整個應用:是指從應用啟動到應用結束。application裡的變量存活時間最長,如果不進行手動删除,它們就一直可以使用。