雖然咱們都是面向Servlet API的接口規範編程,可是仍是應該瞭解一下web服務器是如何實現它的(以tomcat爲例).html
Servlet規範是這樣定義相關的接口:java
1.ServletResponse:Defines an object to assist a servlet in sending a response to the client. The servlet container creates a ServletResponse object and passes it as an argument to the servlet' s service method. 2.ServletRequest:Defines an object to assist a servlet in sending a response to the client. The servlet container creates a ServletResponse object and passes it as an argument to the servlet's service method.
而在相對應的HttpServletResponse和HttpServletRequest無非是處理具體有關HTTP協議的接口.但是在應用服務器Tomcat中是如何產生相對應的對象的呢??咱們看看究竟實現類是哪一個類??web
public class ServletDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(response.getClass().getName()); } } Output: org.apache.catalina.connector.ResponseFacade
下面一張圖簡單介紹響應對象和請求對象如何在Tomcat容器中實現:apache
上圖是 Tomcat 建立的 Request 和 Response 的類結構圖。 Tomcat一接受到請求首先將會建立 org.apache.coyote.Request 和 org.apache.coyote.Response,這兩個類是 Tomcat 內部使用的描述一次請求和相應的信息類它們是一個輕量級的類,它們做用就是在服務器接收到請求後,通過簡單解析將這個請求快速的分配給後續線程去處理,因此它們的對象很小,很容易被 JVM 回收。 接下去當交給一個用戶線程去處理這個請求時又建立 org.apache.catalina.connector.Request 和 org.apache.catalina.connector.Response 對象。 這兩個對象一直穿越整個 Servlet 容器直到要傳給 Servlet,傳給Servlet的是Request和Response的門面類 RequestFacade 和RequestFacade,這裏使用門面模式的目的——封裝容器中的數據。
一次請求對應的Request和Response的類轉化以下圖所示:
Extends the ServletResponse interface to provide HTTP-specific functionality in sending a response. For example, it has methods to access HTTP headers and cookies.The servlet container creates an HttpServletRequest object and passes it as an argument to the servlet's service methods (doGet, doPost, etc).
Tomcat實現HTTPServletResponse 接口的Response對象表明一次請求的響應,這個對象中封裝了向客戶端發送數據、發送響應頭,發送響應狀態碼的方法.接口中方法具體能夠查看Servlet API.基本上是有關HTTP協議的響應消息方法.編程
省略相關方法.........瀏覽器
利用response對象的幾個經常使用示例:tomcat
1.向客戶端輸出中文數據 2.解決中文文件下載 3.控制客戶端不要緩衝 4.發送HTTP頭,控制頁面定時刷新或者跳轉到其餘組件(Servlet/JSP/HTML...) 5.經過HTTP頭,實現請求重定向.
實現核心代碼以下:服務器
1.1向客戶端輸出中文數據(字節流輸出),默認採用本地編碼輸出(響應).若是要以其餘編碼格式響應,有三種實現方法.
package com.itheima.response; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class OutputStreamDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String str = "中國是一個偉大的國家"; //默認本地編碼,GBK編碼格式發送給瀏覽器.而瀏覽器默認用gb2312解碼 // response.getOutputStream().write(str.getBytes()); //數據以utf-8編碼格式發送給瀏覽器. // response.getOutputStream().write(str.getBytes("utf-8")); //解決方案: //1.手動修改瀏覽器解碼方式.IE頁面中任意右擊----->編碼----->Unicode(utf-8) //2.在程序修改響應頭信息...Content-Type:text/html;charset=utf-8 //注意:在修改頭信息按常理應當放在第一行中,必須先設置響應頭,後才能獲得輸出流,向輸出流輸出數據 // response.setHeader("Content-Type", "text/html;charset=utf-8"); // response.getOutputStream().write(str.getBytes("utf-8")); //?爲何不使用close()方法關閉資源流,由於Tomcat應用服務器在響應以後會自動爲程序關閉OutputStream流 //3.使用<meta>標籤模仿響應頭 // response.getOutputStream().write("<meta http-equiv=Content-Type content=text/html;charset=utf-8>".getBytes()); // response.getOutputStream().write((str+"1111").getBytes("utf-8")); //4.使用response對象中setContentType設置瀏覽器以哪一種方式解碼 response.setContentType("text/html;charset=utf-8"); response.getOutputStream().write((str+"2222").getBytes("utf-8")); } }
1.2向客戶端輸出中文數據(字符流輸出).默認是使用iso-8859-1編碼。注意:setContentType功能很強大..
package com.itheima.response; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class PrintWriterDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String str = "美國式范德薩進口量發大水了金卡"; //因爲向瀏覽器輸出字符流,默認是使用iso-8859-1編碼.而瀏覽器可能用別的碼錶解碼數據. // response.getWriter().write(str); //??????????????? //1.告知瀏覽器用什麼編碼. 2.通知服務器輸出用什麼編碼 //做用至關於以上兩條代碼response.setCharacterEncoding("utf-8") // response.setHeader("Content-Type", "text/html;charset=utf-8"); response.setContentType("text/html;charset=utf-8"); //向瀏覽器代表程序是使用utf-8編碼格式輸出的. // response.setCharacterEncoding("utf-8"); response.getWriter().write(str); } }
2.解決中文文件下載.URLEncoder.encode("文件名","編碼格式");
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name="中國.gif"; response.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(name,"utf-8")+""); response.setHeader("Content-Type", "application/octet-stream"); InputStream in = new FileInputStream(this.getServletContext().getRealPath("/WEB-INF/classes/中國.gif")); OutputStream out = response.getOutputStream(); int len = -1; byte[] buf = new byte[1024]; while((len=in.read(buf))!=-1){ out.write(buf, 0, len); } in.close(); out.close(); }
3.控制客戶端不要緩衝
response.addHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Expires", "0");
4.發送HTTP頭,控制頁面定時刷新或者跳轉到其餘組件(Servlet/JSP/HTML...)
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); response.setHeader("Refresh", "3;url="+this.getServletContext().getContextPath()+"/index.jsp"); response.getWriter().write("註冊成功,3秒後會自動跳轉到主頁<br/>"+"若是沒有跳轉,<a href=#>請點擊</a>"); }
5.經過HTTP頭,實現請求重定向.
response.setStatus(302); response.setHeader("Location", this.getServletContext().getContextPath()+"/index.jsp"); 或者 response.sendRedirect(location);
請求重定向示意圖:能夠查看PPT裏(幻燈片放映模式).cookie
Defines an object to provide client request information to a servlet. The servlet container creates a ServletRequest object and passes it as an argument to the servlet's service method.A ServletRequest object provides data including parameter name and values, attributes, and an input stream. Interfaces that extend ServletRequest can provide additional protocol-specific data (for example, HTTP data is provided by HttpServletRequest)
HttpServletRequest對象表明客戶端的請求,當客戶端經過HTTP協議訪問服務器時,HTTP請求頭中的全部信息都封裝在這個對象中,開發人員經過這個對象的方法,能夠得到客戶這些信息。對於相關方法能夠,查看API.幾乎都是get開頭的方法.由於從瀏覽器發送過來,須要服務器程序獲取,而且拿來處理和操做.oracle
一樣,省略。。。。。。
而利用request對象開發經常使用示例:
1.得到客戶機請求頭 2.獲取客戶機請求參數(重要). 3.請求轉發和包含(在轉發中傳遞request域數據)
第一個示例省略,重要是第二個開發示例。。經常使用.
2.將請求參數封裝到JavaBean。利用BeanUtils第三方框架,填充數據.注意:複雜類型(引用型對象)須要註冊對應的轉換器
/** * 將HTTP協議請求相關信息填充到JavaBean 使用第三方開發架包直接實現.開發時經常使用 * @param request * @param clazz * @return bean */ public static <T> T request2Bean(HttpServletRequest request, Class<T> clazz) { try { T t = clazz.newInstance(); // 封裝複雜類型時,須要註冊說明. ConvertUtils.register(new DateLocaleConverter(), Date.class); // 封裝到Bean中. BeanUtils.populate(t, request.getParameterMap()); return t; } catch (Exception e) { new RuntimeException(e); } return null; }
在第三種方式也是經常使用的.可是當你瞭解到轉發和包含原理以後.實驗起來很簡單的..其中包含是不包括頭信息的。。。
而轉發的示例圖:能夠查看本身的PPT,不是偷懶,而是PPT中的畫的太形象..轉發是一次請求...
request中處理請求參數中文處理:
注意:URL的路徑問題:/表明當前應用.URL通常被服務器使用的話能夠直接/,而若是瀏覽器使用的話,則須要/應用名.
例如:URL:/myapp/servlet/ServletDemo1------->服務器用:/servlet/ServletDemo1
-------->瀏覽器用:/myapp/servlet/ServletDemo1
參考資料:
http://docs.oracle.com/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/