《JavaWeb從入門到改行》那些年一起學習的Servlet


Servlet是什么?

Servlet是JavaWeb的三大組件之一。 作用類似銀行前台接待:

  • 接收請求數據 (詢問來辦業務的客戶)
  • 處理請求 (把客戶辦理的業務丟給后台服務器執行)
  • 完成響應 (辦理好了和客戶說一聲)

每個Servlet(接待)都不同,是Tomcat(銀行大廳內的提示語)負責把不同的請求(客戶)發送給(引導給)不同的Servlet(前台接待)。如下圖所示:

20170429

Servlet類由我們來編寫,但是對象是服務器創建好了的,對象的方法也是由服務器調用。並且一個Servlet類只有一個對象。

Servlet API中各個接口之間的關系

,Servlet API中一共有4個Java包

20170426

如何讓瀏覽器訪問Servlet ?

在web.xml文件中指定Servlet的訪問路徑

<servlet>
  <servlet-name>自己起的名字1</servlet-name>
  <servlet-class>包.類</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>自己起的名字1</servlet-name>
  <url-pattern>/自己起的名字2</url-pattern>
</servlet-mapping>

瀏覽器訪問 ; http://localhost:8080/項目名字/自己起的名字2 。通過和url-pattern匹配獲得servlet-class的一個字符串,然后服務器(Tomcat)通過反射Class.forName來得到一個類的對象c ,然后c.newInstance()來獲得一個實例。 通過c.getMethod("service",ServletRequest.class,ServletResoponse.class) 來得到一個Method對象m 。然后通過m.invokie()來完成對service方法的調用 。

如果有form表單,則action="/項目名/自己起的名字2" 。

一個Servlet的生命周期

一個Servlet在服務器(tomcat)開啟的時或者第一次被訪問時被創建,隨着tomcat的關閉而銷毀。

	   // Servlet創建后執行一次
	   public void init(ServletConfig servletConfig) throws ServletException {}
	   //每次處理請求都會執行一次
	   public void service(ServletRequest request, ServletResponse response)
			throws ServletException, IOException {}
	  //Servlet銷毀之前執行一次
	   public void destroy() {}

為什么繼承HttpServlet類是實現Servlet最主流的方式 ?

實現Servlet的方式一共有三種:

  • 實現javax.servlet.Servlet接口;
  • 繼承javax.servlet.GenericServlet類
  • 繼承javax.servlet.http.HttpServlet類;

每創建一個Servlet類都需要手工覆寫Servlet接口中的所有方法,而我們需要每次覆寫的只是service(ServletRequest req, ServletResponse res),所以其他的覆寫會成為程序員的累贅,GenericServlet 抽象類簡化了這種麻煩的工作,這個類為Servlet接口和ServletConfig接口提供所有的默認方法實現,並且能夠在init()中保存ServletConfig對象。這樣,程序員除了覆寫需要覆寫的方法外,其他方法都可以不用手工編寫,一鍵繼承方法都被寫好的GenericServlet抽象類就可以了。但是,瀏覽器與服務器交互,最主流的是http協議,且有7種提交方式,常見的有get和post兩種。所以自己創建的Serlvet需要程序員手工編寫有對應的get和post方法,這又成了程序員的累贅。於是中間類HttpServlet就應運而生,HttpServlet類為我們提供了這兩種方法。

類學習(一):HttpServlet 類

HttpServlet類繼承了GenericServlet類,所以擁有Init()、destroy()等生命周期方法。使用HttpServlet類,還需要使用HttpServletRequest對象和HttpServletResponse對象。

根據API提供,HttpServlet類有如下的幾種方法:

void doDelete(HttpServletRequest req, HttpServletResponse resp) 
		  Called by the server (via the service method) to allow a servlet to handle a DELETE request. 
protected  void doGet(HttpServletRequest req, HttpServletResponse resp) 
		  Called by the server (via the service method) to allow a servlet to handle a GET request. 
protected  void doHead(HttpServletRequest req, HttpServletResponse resp) 
		  Receives an HTTP HEAD request from the protected service method and handles the request. 
protected  void doOptions(HttpServletRequest req, HttpServletResponse resp) 
		  Called by the server (via the service method) to allow a servlet to handle a OPTIONS request. 
protected  void doPost(HttpServletRequest req, HttpServletResponse resp) 
		  Called by the server (via the service method) to allow a servlet to handle a POST request. 
protected  void doPut(HttpServletRequest req, HttpServletResponse resp) 
		  Called by the server (via the service method) to allow a servlet to handle a PUT request. 
protected  void doTrace(HttpServletRequest req, HttpServletResponse resp) 
		  Called by the server (via the service method) to allow a servlet to handle a TRACE request. 
protected  long getLastModified(HttpServletRequest req) 
		  Returns the time the HttpServletRequest object was last modified, in milliseconds since midnight January 1, 1970 GMT. 
protected  void service(HttpServletRequest req, HttpServletResponse resp) 
		  Receives standard HTTP requests from the public service method and dispatches them to the doXXX methods defined in this class. 
 void service(ServletRequest req, ServletResponse res) 
		  Dispatches client requests to the protected service method. 

HttpServlet的運作機理是服務器調用生命周期方法service(ServletRequest req, ServletResponse res) ,將參數req和res強轉為http協議相關的類型,然后調用本類的 service(HttpServletRequest req, HttpServletResponse resp) ,這個方法會通過request得到當前請求的請求方式是get(超鏈接)還是post(表單),然后根據請求方式再調用doGet()方法或者doPost()方法。如下圖時序圖所示:

20170427

接口學習(一):ServletConfig

一個Servlet的配置信息如下

	<servlet>
		<servlet-name>xxx</servlet-name>
		<servlet-class>cn.itcast.web.servlet.AServlet</servlet-class>
		<init-param> //初始化參數1
			<param-name>p1</param-name> //初始化參數名字
			<param-value>v1</param-value>//初始化參數值
		</init-param>
		<init-param>//初始化參數2
			<param-name>p2</param-name>
			<param-value>v2</param-value>
		</init-param>
	</servlet>

Servlet容器在初始化期間將的以上配置信息加載到ServletConfig對象。ServletConfig對象是由服務器創建的,然后傳遞給Servlet的init()方法。所以ServletConfig對象可以使用ServletConfig接口中的方法在init()方法中返回配置信息。根據API提供的ServletConfig接口的方法有如下:

  1. String getServletName() 返回servlet-name中的內容 (無用)
  2. ServletContext getServletContext() 返回Servlet上下文內容 (有用)
  3. String getInitParameter(String name) 通過參數名稱返回對應的值 (無用)
  4. Enumeration getInitParameterName() 返回所有初始化參數的名稱集合 (無用)
public void init(ServletConfig servletConfig) throws ServletException {	
		// 獲取初始化參數
		System.out.println(servletConfig.getInitParameter("p1"));
		System.out.println(servletConfig.getInitParameter("p2"));		
		// 獲取所有初始化參數的名稱,集合打印
		Enumeration e = servletConfig.getInitParameterNames();
		while(e.hasMoreElements()) {
			System.out.println(e.nextElement());
		}

接口學習(二)_域對象學習(一): ServletContext

ServletlContext是javaWeb 四大域對象之一,常稱為application域。 一個項目中只有一個ServletContext對象 ,一個項目中的多個Servlet共用一個ServletContext對象。

ServletContext對象與Tomcat同生共死,在Tomcat啟動時創建,在Tomcat關閉時死亡。常稱為application(應用程序)

獲取ServletContext :

  • HttpServlet繼承了GenericServlet,GenericServlet繼承了Servlet,而Servlet中有個方法 getServletContext(), 所以在HttpServelt中,可以用this.getServletContext()來獲取ServletContext
  • 在init()中通過ServletConfig對象的getServletContext()方法來獲取ServletContext
  • 在HttpSession接口中,有getServletContext()來獲取ServletContext
  • 在ServletContextEvent類中,提供了getServletContext()來獲取ServletContext

ServletContext接口中的一些方法

 java.lang.String getRealPath(java.lang.String path)   //獲取帶有盤符的項目資源路徑
		  Gets the real path corresponding to the given virtual path. 
 java.util.Set<java.lang.String> getResourcePaths(java.lang.String path) //獲取當前項目某一路徑下的所有資源
		  Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path matches the supplied path argument.          
 java.io.InputStream getResourceAsStream(java.lang.String path)  //獲取資源的路徑,再創建輸入流對象
		  Returns the resource located at the named path as an InputStream object. 

application域存取數據功能 代碼演示:

/*
 * AServlet把數據存在域對象ServletContext中,BServlet從域對象中取出數據。
 *  由此可見,ServletContext對象一個項目只有一個,多個Servlet共用一個ServletContext對象,可以在兩個Servlet之間傳遞數據,成為Servlet們之間交流的橋梁
*/
public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 獲取ServletContext對象
		 * 2. 調用其setAttribute()方法完成保存數據
		 */
		ServletContext application = this.getServletContext();
		application.setAttribute("name", "張三");
	}
}
public class BServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 獲取ServletContext對象
		 * 2. 調用其getAttribute()方法完成獲取數據
		 */
		ServletContext application = this.getServletContext();
		String name = (String)application.getAttribute("name");
		System.out.println(name);
	}
}

application域獲取項目文件路徑 代碼演示:

public class DServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 獲取項目index.jsp的帶有盤符的路徑
		 */
		String path = this.getServletContext().getRealPath("/index.jsp");
		System.out.println(path);		
		/*
		 * 獲取資源的路徑后,再創建出輸入流對象!
		 */
		InputStream input = this.getServletContext().getResourceAsStream("/index.jsp");		
		/*
		 * 獲取WEB-INF路徑下所有資源的路徑!
		 */
		Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF");
		System.out.println(paths);
	}
}

F:\apache-tomcat-7.0.73\webapps\ServletDemo_01\index.jsp
[/WEB-INF/lib/, /WEB-INF/classes/, /WEB-INF/web.xml]

接口學習(三)_域對象學習(二)客戶的請求:HttpServletRequest

HttpServletRequest接口繼承了ServletRequest接口,與ServletRequest不同的是,HttpServletRequest是與 Http協議 相關的接口 。

在客戶端發出每個請求時,服務器都會創建一個request對象,並把請求數據封裝到request中,然后在調用Servlet.service()方法時傳遞給service()方法,這說明在service()方法中可以通過request對象來獲取請求數據。

ServletlRequest是javaWeb 四大域對象之一 。 封裝了客戶端所有的請求數據(請求行、請求頭、空行、請求體(GET沒有請求體)),通過接口中的方法,可以獲取這些請求數據

HttpServletRequest提供了請求轉發和請求包含功能。

API中對HttpServletRequest接口提供的有關獲取信息的方法 :

獲取常用信息相關的方法

 java.lang.String getRemoteAddr()  //獲取客戶端IP  ,在父接口ServletRequest中
		  Returns the Internet Protocol (IP) address of the client or last proxy that sent the request. 
  java.lang.String getMethod()          //獲取請求方式,Servlet用獲取的請求方法來判斷是調用doGet還是doPost方法
		  Returns the name of the HTTP method with which this request was made, for example, GET, POST, or PUT.

獲取請求頭相關的方法

 java.lang.String getHeader(java.lang.String name)   //獲取Http請求頭,適用於單值
		  Returns the value of the specified request header as a String. 
 java.util.Enumeration<java.lang.String> getHeaders(java.lang.String name)   //獲取Http請求頭,適用於多值請求頭
		  Returns all the values of the specified request header as an Enumeration of String objects.          

獲取URL相關的方法

http://localhost:8080/servletTest/AServlet?username=xxxx&password=xxx
 java.lang.String getQueryString()  //獲取參數部分 username=xxxx&password=xxx
		  Returns the query string that is contained in the request URL after the path. 
 java.lang.String getRequestURI() //獲取請求URL  servletTest/AServlet
		  Returns the part of this request  URL from the protocol name up to the query string in the first line of the HTTP request. 
 java.lang.StringBuffer getRequestURL() //獲取請求URLhttp://localhost:8080/servletTest/AServlet
		  Reconstructs the URL the client used to make the request.   
 /**
 * 以下方法來自於父接口 ServletRequest
 */        
 java.lang.String getScheme()  //獲取協議,http
		  Returns the name of the scheme used to make this request, for example, http, https, or ftp. 
 java.lang.String getServerName() //獲取服務器名,localhost
		  Returns the host name of the server to which the request was sent. 
 int getServerPort() //獲取服務器端口,8080
		  Returns the port number to which the request was sent. 
 ServletContext getServletContext() //獲取項目名,/servletTest
		  Gets the servlet context to which this ServletRequest was last dispatched. 

獲取請求參數相關的方法 ,請求參數是客戶端發送給服務器的參數,如果在請求體中就是post請求,如果在URL之后,就是get請求

 java.lang.String getParameter(java.lang.String name)   //獲取指定名稱的請求參數值,適用於單值請求參數
		  Returns the value of a request parameter as a String, or null if the parameter does not exist.          
 java.util.Map<java.lang.String,java.lang.String[]> getParameterMap() //獲取所有請求參數封裝到Map中,其中key為參數名,value為參數值。
		  Returns a java.util.Map of the parameters of this request. 
 java.util.Enumeration<java.lang.String> getParameterNames() //獲取所有請求參數名稱
		  Returns an Enumeration of String objects containing the names of the parameters contained in this request. 
 java.lang.String[] getParameterValues(java.lang.String name) //獲取指定名稱的請求參數值,適用於多值請求參數,如表單中多個愛好
		  Returns an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist. 

小案列 :

/**
*  獲取常用信息案例,並通過User-Agent識別用戶瀏覽器類型
*/
public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String addr = request.getRemoteAddr(); //獲取客戶端的IP地址				
						   System.out.println("請求方式:" + request.getMethod());//獲取請求方式
						   /**
						   * 通過User-Agent識別用戶瀏覽器類型
						   */
		String userAgent = request.getHeader("User-Agent");//獲取名為User-Agent的請求頭!	
		// 是否包含字符串Chrome,如果包含,說明用戶使用的是google瀏覽器
		if(userAgent.toLowerCase().contains("chrome")) {
			System.out.println("您好:" + addr + ", 你用的是谷歌");
		} else if(userAgent.toLowerCase().contains("firefox")) {
			System.out.println("您好:" + addr + ", 你用的是火狐");
		} else if(userAgent.toLowerCase().contains("msie")) {
			System.out.println("您好:" + addr + ", 你用的是IE");
		}
	}
}
/**
*  Referer請求頭實現防盜鏈
* 防盜鏈 : 防止一個網站的超鏈接,鏈接到別的網站的資源上。
*/
public class BServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//使用Referer請求頭,來防盜鏈
				 String referer = request.getHeader("Referer");//輸出鏈接網站的來源
		//System.out.println(referer);    
		if(referer == null || !referer.contains("localhost")) {
			response.sendRedirect("http://www.baidu.com");
		} else {
			System.out.println("hello!");
		}	
	}
}
/**
*  演示 服務器獲取客戶端的參數
*/
/**
* 客戶端對服務器的get請求(超鏈接)和post請求(表單)
*/
<a href="/servletTest/CServlet?username=admin&password=123456">點擊這里</a>  
<form action="/servletTest/CServlet" method="post">
		  用戶名:<input type="text" name="username"/><br/>
		  密 碼:<input type="password" name="password"/><br/>
		  愛 好:<input type="checkbox" name="hobby" value="lq"/>籃球
						 <input type="checkbox" name="hobby" value="ymq"/>羽毛球
						<input type="checkbox" name="hobby" value="ppq"/>乒乓球
  <br/>
  <input type="submit" value="提交"/>
</form>
/**
* Servlet獲取請求參數
* 
*/
public class CServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/**
		*  在doGet方法中獲取get請求方法的參數
		*/		
		System.out.println("GET: " + request.getParameter("username"));
		System.out.println("GET: " + request.getParameter("password"));
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String username = request.getParameter("username");//獲取單值
		String password = request.getParameter("password");
		String[] hobby = request.getParameterValues("hobby");//獲取多值		
		System.out.println(username + ", " + password + ", " + Arrays.toString(hobby));		
		/*
		 *  獲取所有請求參數的名稱
		 */
		Enumeration names = request.getParameterNames();
		while(names.hasMoreElements()) {
			System.out.println(names.nextElement());
		}		
		/*
		 * 獲取所有請求參數,封裝到Map中
		 */
		Map<String,String[]> map = request.getParameterMap();
		for(String name : map.keySet()) {   //獲取參數名字
			String[] values = map.get(name);   //根據參數名字獲取參數值
			System.out.println(name + "=" + Arrays.toString(values));
		}
	}
}

請求轉發和請求包含

請求轉發/包含是對於一個請求來說,如果一個Serlvet 完成不了的話,需要轉發給另一個Servlet幫助完成。即,一個請求 跨多個Servlet 。無論是請求轉發還是請求包含,都在一個請求和一個響應范圍內! 使用同一個request和response!如下圖所示

20170430

請求轉發和請求包含的區別是: 請求轉發中,AServlet把響應體(要處理的任務)全部交給BServelt去做 ,AServlet即使做了工作,也是無效的。所以 ,雖然AServlet可以設置響應體,但是沒有用,不能在客戶端輸出。 BServlet設置的響應體才能才客戶端輸出 。 兩者都可以設置響應頭,並且都對客戶端有用。注意: 當AServlet做的工作非常多的時候,會拋出異常,而且能在客戶端有效。
請求包含中,AServelt與BServlet共同完成響應體,所以既能在客戶端輸出響應頭,也可以輸出響應體。 在實際項目中,如果是請求轉發,則AServlet不應該再做任何工作,完全讓BServlet完成。

 RequestDispatcher getRequestDispatcher(java.lang.String path) //使用request獲取RequestDispatcher對象,方法的參數是被轉發或包含的Servlet的Servlet路徑
		  Returns a RequestDispatcher object that acts as a wrapper for the resource located at the given path. 
/**
* 在RequestDispatcher接口中有如下方法:
*/          
void forward(ServletRequest request, ServletResponse response) //轉發
		  Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server. 
 void include(ServletRequest request, ServletResponse response) //包含
		  Includes the content of a resource (servlet, JSP page, HTML file) in the response. 

ServletRequest域對象(request域) :

ServletRequest是域對象,常稱為request域。 請求轉發和請求包含都需要在多個Servlet之間進行,request域正好是多個的Servlet之間交流的橋梁。request域通常用在兩個Servlet的請求轉發和請求包含中。

小案列 :

/**
 * 請求轉發
 * OneServlet轉發到TwoServlet中
 */
public class OneServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setHeader("aaa", "AAA");//設置響應頭	
				  // 設置響應體,這個響應體是無效的,因為在后面有個轉發
		response.getWriter().print("a");		
		/*
		 * 向reuqest域中添加一個屬性
		 */
		request.setAttribute("username", "zhangsan");
		/**
		* 請求轉發 
		*等同與調用TwoServlet的service()方法。
		*/
		request.getRequestDispatcher("/TwoServlet").forward(request, response);		
	}
}
public class TwoServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println(request.getAttribute("username"));
		/**
						   *  設置響應體,有效,可以在客戶端顯示 
		*/
		response.getWriter().print("hello TwoServlet!");//設置響應體
	}
}

請求編碼:

瀏覽器所用的超鏈接和表單的請求參數一般是utf-8編碼,但是服務器默認使用iso-8859-1來處理參數,產生亂碼。

 void setCharacterEncoding(java.lang.String env) 
		  Overrides the name of the character encoding used in the body of this request. 

對於post請求,只需要在獲取參數getparameter()之前調用 request.setCharacterEncoding("utf-8")即可。對於get請求,則用如下方式:

String name = request.getParameter("name");//假設得到的是name 
/**
* 反編
*/
byte[] bytes = name.getBytes("ISO-8859-1");
name =  new String (bytes,"utf-8");

接口學習(四)_服務器的響應:HttpServletResponse

HttpServletResponse接口繼承了ServletResponse接口,與ServletResponse不同的是,HttpServletResponse是與 Http協議 相關的接口 。

HttpServletResponse對象是客戶端向服務器請求時,服務器創建的一個對象,然后傳入到HttpServlet類的service(HttpServletRequest req, HttpServletResponse resp) 方法中,是Servlet用來向客戶端響應的"有效工具" 。 響應的對象是客戶端,也就是給瀏覽器發送信息。以下的方法都是與瀏覽器打交道。

API中對HttpServletResponse接口提供某些重要方法 :

發送狀態碼有關的方法, 發送狀態碼是Servlet利用response向瀏覽器發送錯誤/成功的狀態 :

 void sendError(int sc)   //發送錯誤狀態碼 ,如404
		  Sends an error response to the client using the specified status code and clears the buffer. 
 void sendError(int sc, java.lang.String msg)   // 發送錯誤狀態碼 ,可以帶一個錯誤信息
		  Sends an error response to the client using the specified status and clears the buffer. 
 void setStatus(int sc)    // 發送成功的狀態碼 
		  Sets the status code for this response. 

響應頭有關的方法,響應頭是Servlet利用response向瀏覽器發送怎樣的響應,瀏覽器能認識這些頭 :

 void setHeader(java.lang.String name, java.lang.String value)   // 適用於單值的響應頭
		  Sets a response header with the given name and value. 
 void setIntHeader(java.lang.String name, int value)     //適用於單值的Int類型的響應頭
		  Sets a response header with the given name and integer value. 
void setDateHeader(java.lang.String name, long date)  //適用於單值的毫秒類型的響應頭
		  Sets a response header with the given name and date-value.           

<meta>標簽可以代替響應頭

重定向相關的方法,重定向是Servlet利用response向瀏覽器重定向信息 :

 void sendRedirect(java.lang.String location) 
		  Sends a temporary redirect response to the client using the specified redirect location URL and clears the buffer. 

響應正文(響應體)有關的方法,響應體是Servlet利用response向瀏覽器發送內容:

既然是發送內容,所以用到response提供的兩個響應流,根據異常的提示,可以發現在一個請求中,不能同時使用這兩個流!這兩個響應流的方法在HttpServletResponse的父類ServletResponse中。

 ServletOutputStream getOutputStream()    //用來向客戶端發送字節數據
		  Returns a ServletOutputStream suitable for writing binary data in the response. 
		  Throws:              //用這個方法需要拋出一個異常
					  UnsupportedEncodingException - if the character encoding returned by getCharacterEncoding cannot be used 
					  IllegalStateException - if the getOutputStream method has already been called for this response object 
					  java.io.IOException - if an input or output exception occurred
					  java.io.PrintWriter getWriter() 
					  Returns a PrintWriter object that can send character text to the client.        
 java.io.PrintWriter getWriter()  //用來向客戶端發送字符數據!需要設置編碼
		  Returns a PrintWriter object that can send character text to the client.                        

小案列 :

/*
 *  利用響應頭實現重定向
 * 重定向 : 本來訪問的http;//localhost:8080/test/AServlet , 但是會訪問到http;//localhost:8080/test/BServlet 
*/
public class BServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("BServlet");		
		/*
		 * 重定向:
		 * 1. 設置Location頭
		 * 2. 發送302狀態碼
		 */
		response.setHeader("Location", "/項目名/要重定向的頁面");
		response.setStatus(302);  		
		/*
		 *快捷的重定向方法
		 */
		response.sendRedirect("/項目名/要重定向的頁面");
		/*
		 * 定時重定向,5秒后跳轉到要重定向的頁面
		 * 設置名為Refresh的響應頭
		 */
		response.setHeader("Refresh", "5;URL=/項目名/要重定向的頁面");
	}
}

/**
* 禁用瀏覽器緩存
* 瀏覽器緩存: 當代碼變化后,瀏覽器訪問到內容依然是緩存的內容(上一次訪問的內容)
*/
public class FServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 利用Cache-Control、pragma、expires這三個頭
		 */
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("pragma", "no-cache");
		response.setDateHeader("expires", -1);
	}
}
public class BServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/**
						   * 響應字符數據 
		*/
		PrintWriter writer = response.getWriter();
		writer.print("world");
		/**
							*響應字節數據 1 _字符數據的另一種實現方式,等同於上一個的響應字符數據 的功能
							* 1. 將字符串變成字節
							* 2. 用字節流輸出
						   */
		String s = "Hello World";
		byte[] bytes = s.getBytes();
		response.getOutputStream().write(bytes);
		/**
		 * 響應字節數據 2_把一張圖片讀取到字節數組中
		 * IOUtils類是自己編寫的一個小工具,需要導入commons-io-1.4.jar, 可以到文章尾部尋找下載鏈接
		 */
		String path = "F:/a.jpg";
		FileInputStream in = new FileInputStream(path);
				 byte[] bytes = IOUtils.toByteArray(in);//讀取輸入流內容的字節到字節數組中。
				 response.getOutputStream().write(bytes);
		//IOUtils.copy(in, response.getOutputStream());
	}
}

響應編碼 :

服務器通過response.getWriter()向客戶端發送響應字符數據默認編碼是iso-8859-1,但是一般瀏覽器會把數據當成gbk來解碼。 所以服務器要設置編碼為utf-8。 並且用響應頭來告訴瀏覽器,瀏覽器就會用urf-8來解碼。這樣兩邊都是utf-8。就不會產生亂碼 。

void setCharacterEncoding(java.lang.String charset)  //設置編碼
		  Sets the character encoding (MIME charset) of the response being sent to the client, for example, to UTF-8. 
response.setHeader("Content-type","text/html;charset=utf-8")或者response.setContentType("text/html;charset=utf-8")   //    設置響應頭   

值得注意的是,設置響應頭的方法已經包含了對編碼的設置,所以在用getWriter()方法給客戶端響應之前,都調用一次response.setContentType("text/html;charset=utf-8") 即可 。

類學習(二):Cookie

Cookie是HTTP協議制定的!由服務器創建保存到客戶端瀏覽器的一個鍵值對!是保存在客戶端

瀏覽器第一次訪問服務器時,服務器會隨着對客戶端的響應將Cookie發送給瀏覽器,瀏覽器把Cookie保存起來,下次瀏覽器請求服務器時會將上一次請求中得到的Cookie隨着請求歸還給服務器,服務器會獲取這個瀏覽器的Cookie,這時服務器就知道你就是上次的那個瀏覽器。在這個過程中,服務器通過Set-Cookie響應頭將Cookie的鍵值發送給瀏覽器,代碼是response.addHeader("Set-Cookie", "鍵=值") 。瀏覽器通過Cookie請求頭歸還給服務器,代碼是request.getHeader("Cookie")。 但是這種有頭的代碼都不是當下流行的方式,在HttpServletRequest 和 HttpServletResponse中有專門的兩個便捷的方法來替代以上的兩個方法: repsonse.addCookie()向瀏覽器保存Cookie和request.getCookies()獲取瀏覽器歸還的Cookie 。在API中,對這兩個方法的定義如下:

/**
* 方法來自於HttpServletRequest接口和HttpServletResponse接口
*/
 void addCookie(Cookie cookie) 
		  Adds the specified cookie to the response. 
 Cookie[] getCookies()   //返回的是Cookie數組
		  Returns an array containing all of the Cookie objects the client sent with this request. 

另外,由於瀏覽器的速度與空間占有問題,1個Cookie的大小是有限制的(小於4KB),1個服務器最多向1個瀏覽器保存20個Cookie,1個瀏覽器最多可以保存300個Cookie ,現在的瀏覽器會多多少少的超出一點。

由於Cookie的特性,服務器可以使用Cookie來跟蹤客戶端的狀態,所以多用來實現購物車系統,顯示上次登錄名等功能 。

	/**
	 * Cookie的保存
	 */
	Cookie cookie1 = new Cookie("aaa", "AAA");
	response.addCookie(cookie1);
	/**
	* 獲取Cookie
	*/
	Cookie[] cookies = request.getCookies();
	if(cookies != null) {
		for(Cookie c : cookies) {  //遍歷獲取Cookiede 鍵值
			out.print(c.getName() + "=" + c.getValue() + "<br/>");
		}
	}

Cookie的生命周期

Cookie的存活是有時長的,可以通過如下的方法設置Cookie的存活時常 。(以秒為單位)

 void setMaxAge(int expiry) 
		  Sets the maximum age in seconds for this Cookie. 
		   maxAge>0:瀏覽器會把Cookie保存到客戶機硬盤上,有效時長為maxAge的值決定。
		   maxAge<0:Cookie只在瀏覽器內存中存在,當用戶關閉瀏覽器時,瀏覽器進程結束,同時Cookie也就死亡了。
		   maxAge=0:瀏覽器會馬上刪除這個Cookie!原理是把瀏覽器保存的同名Cookie給覆蓋掉

Cookie的路徑;

Cookie的路徑並不是設置這個Cookie在客戶端的保存路徑,而是由服務器創建Cookie時設置 。當瀏覽器訪問服務器某個路徑時,需要歸還哪些Cookie給服務器呢?這由Cookie的path決定。瀏覽器訪問服務器的路徑,如果包含某個Cookie的路徑,那么就會歸還這個Cookie。

比如瀏覽器保存某個Cookie的頁面是path1(http://localhost:8080/CookieTest/cookie/cookieDemo_01.jsp) ,那么這個Cookie的路徑就是path2(http://localhost:8080/CookieTest/cookie),而瀏覽器訪問服務器的path3(http://localhost:8080/CookieTest/cookie/a.jsp ),很明顯,path3包含path2,那么當瀏覽器訪問服務器這個路徑時,需要歸還這個Cookie 。

接口學習(五)_域對象學習(三):HttpSession

什么是一次會話? 什么是會話跟蹤?

會話是客戶端與服務器之間的一次會晤,在一次會晤中可能會包含多次請求和響應。類似於路人甲碰到路人乙,會話開始,期間的談話可以有多次提問和回答,直到兩人離開,會話結束 。 下一次再碰到,即使另一個會話了。在JavaWeb中,客戶向某一服務器發出第一個請求開始,會話就開始了,直到客戶關閉了瀏覽器會話結束,也就是說會話范圍是某個用戶從首次訪問服務器開始,到該用戶關閉瀏覽器結束!(需要注意的是: 並不是重啟瀏覽器,比如打開一個瀏覽器,session域開始生效,然后再打開相同的瀏覽器,還是能夠獲取到這個session,但是不能用其他瀏覽器,不支持跨瀏覽器 。只要第一個瀏覽器不關閉,那就不會死亡)

會話跟蹤技術是在一個會話的多個請求中共享數據。這也是Session域的作用。會話路徑技術使用Cookie或session完成。

HttpSession是什么 ?HttpSession為什么依賴Cookie?原理又是什么?

區別於Cookie,HttpSession是由JavaWeb提供的,用來會話跟蹤的類。session是服務器端對象,保存在服務器端!而Cookie是服務器保存在客戶端瀏覽器中的類 。 HttpSession鎖定的是用戶,一個Session只有一個用戶 。HttpSession 底層依賴Cookie,或是URL重寫!

為什么說底層依賴Cookie ? 當瀏覽器訪問服務器時,服務器在第一次獲取session時(request.getSession()) , 會根據sessionId來選擇要不要創建session,規則如下:

  • 如果sessionId不存在,創建session,把session保存起來,把新創建的sessionId保存到Cookie中
  • 如果sessionId存在,通過sessionId查找session對象,如果沒有查找到,創建session,把session保存起來,把新創建的sessionId保存到Cookie中
  • 如果sessionId存在,通過sessionId查找到了session對象,那么就不會再創建session對象了。

創建的session是保存在服務器端,而給客戶端的是session的id(一個cookie中保存了sessionId)。客戶端通過Cookie帶走的是sessionId,而數據是保存在session中。當客戶端再次訪問服務器時,在請求中會帶上sessionId,而服務器會通過sessionId找到對應的session,而無需再創建新的session。

Servlet通過request.getSession();來獲得Session對象。該方法如下:

 HttpSession getSession() 
		  Returns the current session associated with this request, or if the request does not have a session, creates one. 

session域對象

這里要區分JSP中得到的session對象,session是jsp的內置對象,不用創建就可以直接使用!

HttpSession是javaWeb 四大域對象 之一,作用就是在一次會話期間對多個請求之間起着橋梁作用。在項目工程中,最大的作用就是保存用戶的登陸信息 。

小案例: 驗證碼驗證登陸

項目示意圖如下:

20170503

項目下載地址

/**
*  login.jsp
*/
 <head>
<script type="text/javascript">
/**
 * 
 *      看不清楚換一張
 */
function _change() {
	/*
	1. 得到img元素
	2. 修改其src為/servletDemo/VerifyCodeServlet
	*/
	var imgEle = document.getElementById("img");
	imgEle.src = "/servletTest/VerifyCodeServlet?a=" + new Date().getTime();//加每回都不一樣的參數的意思是取消瀏覽器的緩存
}
</script>
  </head>  
  <body>
	 <h1>登錄</h1>
<%
	/**
	 *      讀取名為uname的Cookie!
	 *       如果為空顯示:""
	 *      如果不為空顯示:Cookie的值
	 */
   String uname = "";
   Cookie[] cs = request.getCookies();//獲取請求中所有的cookie
   if(cs != null) {// 如果存在cookie
	   for(Cookie c : cs) {//循環遍歷所有的cookie
		   if("uname".equals(c.getName())) {//查找名為uname的cookie
			   uname = c.getValue();//獲取這個cookie的值,給uname這個變量
		   }
	  }
   }
%>
<%
   /*
			  獲取request域中保存的錯誤信息
			  用巧妙地方法顯示在頁面中顯示錯誤信息 ,防止第一次登陸就顯示內容。因為如果msg =null,頁面顯示空字符串,對用戶來說,什么都沒有
   */
	String message = "";
	String msg = (String)request.getAttribute("msg");//獲取request域中的名為msg的屬性
	if(msg != null) {
		message = msg;
	}
%>
  <font color="red"><b><%=message %> </b></font>
   <form action="/servletTest/LoginServlet" method="post">
	<%-- 把cookie中的用戶名顯示到用戶名文本框中 --%>
	用戶名:<input type="text" name="username" value="<%=uname%>"/><br/>
	密 碼:<input type="password" name="password"/><br/>
	驗證碼:<input type="text" name="verifyCode" size="3"/>
			<img id="img" src="/servletTest/VerifyCodeServlet"/>
			<a href="javascript:_change()">換一張</a>
	<br/>
	<input type="submit" value="登錄"/>
   </form> 
  </body>
/**
* succ1.jsp 
*/
<body>
<h1>succ1</h1>
<%
String username = (String)session.getAttribute("username");
if(username == null) {
	/*
	1. 向request域中保存錯誤信息,轉發到login.jsp
	*/
	request.setAttribute("msg", "您還沒有登錄!請先進行登陸");
	request.getRequestDispatcher("/login.jsp").forward(request, response);
	return;
}
%>
歡迎<%=username %>進入succ1 頁面!</br>
你可以進入succ2頁面,<a href="/servletTest/succ2.jsp">點擊這兒</a>
  </body>
  /**
* succ2.jsp 
*/
  <body>
<h1>succ2</h1>
<%
String username = (String)session.getAttribute("username");
if(username == null) {
	/*
	1. 向request域中保存錯誤信息,轉發到login.jsp
	*/
	request.setAttribute("msg", "您還沒有登錄!請先進行登陸");
	request.getRequestDispatcher("/login.jsp").forward(request, response);
	return;
}
%>

歡迎<%=username %>進入succ2 頁面!
  </body>
/**
*  VerifyCode類
*/
public class VerifyCode {
	private int w = 70;
	private int h = 35;
	private Random r = new Random();
	// {"宋體", "華文楷體", "黑體", "華文新魏", "華文隸書", "微軟雅黑", "楷體_GB2312"}
	private String[] fontNames  = {"宋體", "華文楷體", "黑體", "微軟雅黑", "楷體_GB2312"};
	// 可選字符,1和L、0和O太相似,不寫入
	private String codes  = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
	// 背景色
	private Color bgColor  = new Color(255, 255, 255);
	// 驗證碼上的文本
	private String text ;	
	// 生成隨機的顏色
	private Color randomColor () {
		int red = r.nextInt(150);
		int green = r.nextInt(150);
		int blue = r.nextInt(150);
		return new Color(red, green, blue);
	}	
	// 生成隨機的字體
	private Font randomFont () {
		int index = r.nextInt(fontNames.length);
		String fontName = fontNames[index];//生成隨機的字體名稱
		int style = r.nextInt(4);//生成隨機的樣式, 0(無樣式), 1(粗體), 2(斜體), 3(粗體+斜體)
		int size = r.nextInt(5) + 24; //生成隨機字號, 24 ~ 28
		return new Font(fontName, style, size);
	}	
	// 畫干擾線
	private void drawLine (BufferedImage image) {
		int num  = 3;//一共畫3條
		Graphics2D g2 = (Graphics2D)image.getGraphics();
		for(int i = 0; i < num; i++) {//生成兩個點的坐標,即4個值
			int x1 = r.nextInt(w);
			int y1 = r.nextInt(h);
			int x2 = r.nextInt(w);
			int y2 = r.nextInt(h); 
			g2.setStroke(new BasicStroke(1.5F)); 
			g2.setColor(Color.BLUE); //干擾線是藍色
			g2.drawLine(x1, y1, x2, y2);//畫線
		}
	}	
	// 隨機生成一個字符
	private char randomChar () {
		int index = r.nextInt(codes.length());
		return codes.charAt(index);
	}	
	// 創建BufferedImage
	private BufferedImage createImage () {
		BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 
		Graphics2D g2 = (Graphics2D)image.getGraphics(); 
		g2.setColor(this.bgColor);
		g2.fillRect(0, 0, w, h);
		return image;
	}	
	// 調用這個方法得到驗證碼
	public BufferedImage getImage () {
		BufferedImage image = createImage();//創建圖片緩沖區 
		Graphics2D g2 = (Graphics2D)image.getGraphics();//得到繪制環境
		StringBuilder sb = new StringBuilder();//用來裝載生成的驗證碼文本
		// 向圖片中畫4個字符
		for(int i = 0; i < 4; i++)  {//循環四次,每次生成一個字符
			String s = randomChar() + "";//隨機生成一個字母 
			sb.append(s); //把字母添加到sb中
			float x = i * 1.0F * w / 4; //設置當前字符的x軸坐標
			g2.setFont(randomFont()); //設置隨機字體
			g2.setColor(randomColor()); //設置隨機顏色
			g2.drawString(s, x, h-5); //畫圖
		}
		this.text = sb.toString(); //把生成的字符串賦給了this.text
		drawLine(image); //添加干擾線
		return image;		
	}	
	// 返回驗證碼圖片上的文本
	public String getText () {
		return text;
	}	
	// 保存圖片到指定的輸出流
	public static void output (BufferedImage image, OutputStream out) 
				throws IOException {
		ImageIO.write(image, "JPEG", out);
	}
}
/**
*  VerifyCodeServlet
*/
public class VerifyCodeServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 生成圖片
		 * 2. 保存圖片上的文本到session域中
		 * 3. 把圖片響應給客戶端
		 */
		VerifyCode vc = new VerifyCode();
		BufferedImage image = vc.getImage();
		request.getSession().setAttribute("session_vcode", vc.getText());//保存圖片上的文本到session域		
		VerifyCode.output(image, response.getOutputStream());
	}
}
/**
* LoginServlet
*/
public class LoginServlet extends HttpServlet {
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 校驗驗證碼
		 *       從session中獲取正確的驗證碼
		 *       從表單中獲取用戶填寫的驗證碼
		 *       進行比較!
		 *       如果相同,向下運行,否則保存錯誤信息到request域,轉發到login.jsp
		 */
		String sessionCode = (String) request.getSession().getAttribute("session_vcode");
		String paramCode = request.getParameter("verifyCode");
		
		if(!paramCode.equalsIgnoreCase(sessionCode)) {
			request.setAttribute("msg", "驗證碼錯誤!");
			request.getRequestDispatcher("/login.jsp").forward(request, response);
			return;  //如果不加return ,則后面的代碼會執行。 驗證碼錯誤,就沒有必要繼續進行用戶和密碼的判斷了 
		}		
		/*
		 * 2. 校驗用戶名和密碼是否正確
		 *      處理亂碼
		 *      獲取表單的數據
		 *      進行比較,用戶名只要不是admin就算登陸成功
		 */		
		request.setCharacterEncoding("utf-8");
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		if(!"admin".equalsIgnoreCase(username)) {//登錄成功
			/*
			 * 5. 添加Cookie,讓瀏覽器記住上一次輸入的用戶名
			 *      把用戶名保存到cookie中,發送給客戶端瀏覽器
			 *      當再次打開login.jsp時,login.jsp中會讀取request中的cookie,把它顯示到用戶名文本框中
			 */
			Cookie cookie = new Cookie("uname", username);//創建Cookie
			cookie.setMaxAge(60*60*24);//設置cookie命長為1天
			response.addCookie(cookie);//保存cookie		
			/*
			 * 3. 如果成功
			 *      獲取session對象
			 *      保存用戶信息到session中
			 *      采用重定向技術鏈接到succ1.jsp,(路徑帶項目名),使用重定向是另一個響應,即使是多個請求和多個響應,session域中的內容也不會丟失。
			 */
			HttpSession session = request.getSession();//獲取session
			session.setAttribute("username", username);//向session域中保存用戶名
			response.sendRedirect("/servletTest/succ1.jsp");
		} else {//登錄失敗
			/*
			 * 4. 如果失敗
			 *    保存錯誤信息到request域中
			 *    采用請求轉發技術鏈接到login.jsp,(路徑不帶項目名),注意,不能使用重定向,因為重定向是另外一個響應,不屬於一次請求范圍了,request域中的內容是丟失
			 */
			request.setAttribute("msg", "用戶名或密碼錯誤!");
			RequestDispatcher qr = request.getRequestDispatcher("/login.jsp");//得到轉發器
			qr.forward(request, response);//轉發
		}
	}
}

補充知識1、 認識http協議

http協議,即超文本傳輸協議。它規定了瀏覽器與服務器之間的通訊規則。http是基於請求/響應模式的,所以分為請求協議和響應協議

請求協議

  • 格式:
  請求首行  (請求方法 請求路徑 請求協議及版本) 
  請求頭    (請求頭就是一些鍵值)
  空行  (就是一個空行,用來與請求體分隔)
  請求體(或稱之為請求正文)(GET方法沒有請求體,POST才有請求體,請求體內容為:參數名=參數值&參數名=參數值,其中參數值為中文,會使用URL編碼。)
  • 常見請求方法有GET和POST
  在瀏覽器地址欄中發送請求,以及點擊超鏈接都是GET請求
  提交表單可以發送GET請求,以及POST請求
  GET請求沒有請求體,但空行是存在的
  POST請求是存在請求體的
  • 常見請求頭
 Host:請求的服務器主機名
  User-Agent:客戶端瀏覽器與操作系統相關信息
  Accept-Encoding:客戶端支持的數據壓縮格式
 Connection:客戶端支持的連接方式
  Cookie:客戶端發送給服務器的“小甜點”,它服務器寄存在客戶端的。如果當前訪問的服務器沒有在客戶端寄存東西,那么就不會存在它!
  Content-Length:請求體的長度
  Referer:當前發出請求的地址,例如在瀏覽器地址欄直接訪問服務器,那么沒有這個請求頭。如果是在www.baidu.com頁面上點擊鏈接訪問的服務器,那么這個頭的值就是www.baidu.com
    作用1:統計來源
     作用2:防盜鏈
   Content-Type:如果是POST請求,會有這個頭,默認值為application/x-www-form-urlencoded,表示請求體內容使用url編碼。

響應協議

  • 格式:
   響應首行
 響應頭
  空行
  響應體(或稱之為響應正文)
  • 狀態碼
   200:請求成功
   302:請求重定向
   304:請求資源沒有改變
   404:請求資源不存在,屬性客戶端錯誤
   500:服務器內部錯誤
  • 常見響應頭
  Content-Type:響應正文的MIME類型,例如image/jpeg表示響應正文為jpg圖片,例如text/html;charset=utf-8表示響應正文為html,並且編碼為utf-8編碼。瀏覽器會通過這一信息來顯示響應數據
  Content-Length:響應正文的長度
  Set-Cookie:服務器寄存在客戶端的“小甜點”,當客戶端再次訪問服務器時會把這個“小甜點”還給服務器
  Date:響應時間,可能會有8小時的誤差,因為中國的時區問題

通知客戶端瀏覽器不要緩存頁面的響應頭:
  Expires:-1
   Cache-Control: no-cache
  Pragma: no-cache
自動刷新響應頭,瀏覽器會在3秒鍾后自動重定向到傳智主頁
   Refresh: 3;url=http://www.itcast.cn

補充知識2、 javaweb四大域對象

PageContext(page域)、ServletRequest(request域)、HttpSession(session域)、ServletContext(application域)。其中request、session、application域名是Sevlet三大域。page域是用在JSP中。 簡單來說, 域對象簡單說就是能在Servlet之間(page域使用在JSP中)傳遞參數,因為要降低耦合度,所以我們創建的每個Servlet之間都是不能相互交流的,可以說,域對象是串聯起多個Servlet的線,可以為多個Servlet之間的交流傳遞數據,這就顯得比較重要。域對象內部有個Map,用來存取數據。

所有的域對象都有如下的方法:

 void setAttribute(java.lang.String name, java.lang.Object o)  //保存值
		  Stores an attribute in this request. 
 java.lang.Object getAttribute(java.lang.String name)  //獲取值
		  Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.          
 void removeAttribute(java.lang.String name)  //移除值
		  Removes an attribute from this request.          
```	

這四個域的范圍不同:

PageContext : 這個范圍是最小的,在JSP中只能在同一個頁面中傳遞傳遞參數。(不屬於本文章講解范圍)
HttpServletRequest:一個請求創建一個request對象,所以在同一個請求中可以共享request,例如一個請求從AServlet轉發到BServlet,那么AServlet和BServlet可以共享request域中的數據;
HttpSession:一個會話創建一個HttpSession對象,同一會話中的多個請求中可以共享session中的數據;瀏覽器不關,不會死亡,在一個瀏覽器不關閉的狀態下,再打開相同的瀏覽器,還是不會死亡,但是打開不同的瀏覽器就不可以訪問 。 
ServletContext:范圍最大的一個域 ,一個應用只創建一個ServletContext對象,所以在ServletContext中的數據可以在整個應用中共享,只要不啟動服務器,那么ServletContext中的數據就可以共享;服務器不關,就不會死亡

# <a name="neizhiduixiang">補充知識3、JSP九大內置對象  </a>

在JSP中有九大內置對象,分別是request對象、response對象、session對象、application對象、out 對象、pageContext 對象、config 對象、page 對象、exception 對象。本文章不涉及到JSP內容,所以不詳細展開,只需要知道內置對象可以不加聲明就在JSP頁面腳本(Java程序片和Java表達式)中使用的成員變量 。要與四大域對象有所區分,四大域對象有三個是用在Servlet中。


# <a name=""> 補充知識2、 請求轉發與重定向的區別</a>

 請求轉發是一個請求一次響應,而重定向是兩次請求兩次響應


請求轉發地址欄不變化,而重定向會顯示后一個請求的地址

請求轉發只能轉發到本項目其他Servlet,而重定向不只能重定向到本項目的其他Servlet,還能定向到其他項目


請求轉發是服務器端行為,只需給出轉發的Servlet路徑,而重定向需要給出requestURI,即包含項目名!


請求轉發和重定向效率是轉發高!因為是一個請求!

需要地址欄發生變化,那么必須使用重定向!

需要在下一個Servlet中獲取request域中的數據,必須要使用轉發!


--------------------------

文章下載 ;

commons-io-1.4.jar下載地址:[http://download.csdn.net/detail/g425680992/9832418](http://download.csdn.net/detail/g425680992/9832418)

<a name="download">項目</a>下載地址:[http://download.csdn.net/detail/g425680992/9832411](http://download.csdn.net/detail/g425680992/9832411)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM