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

Servlet是什麼?

Servlet是JavaWeb的三大組件之一。 做用相似銀行前臺接待:html

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

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

20170429

Servlet類由咱們來編寫,可是對象是服務器建立好了的,對象的方法也是由服務器調用。而且一個Servlet類只有一個對象。程序員

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

,Servlet API中一共有4個Java包web

20170426

如何讓瀏覽器訪問Servlet ?

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

<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方法的調用 。apache

若是有form表單,則action="/項目名/本身起的名字2" 。api

一個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);//轉發
        }
    }
}

補充知識一、 認識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

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

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

全部的域對象都有以下的方法:

java 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中的數據就能夠共享;服務器不關,就不會死亡

補充知識三、JSP九大內置對象

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

補充知識二、 請求轉發與重定向的區別

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

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

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

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

請求轉發和重定向效率是轉發高!由於是一個請求!

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

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


文章下載 ;

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

項目下載地址:http://download.csdn.net/detail/g425680992/9832411

相關文章
相關標籤/搜索