Servlet請求與響應、ServletContext對象

目錄




關於HTTP1.1

概述

HTTP(HyperText Transfer Protocol)超文本傳輸協議,是因特網上應用最爲廣泛的一種網絡傳輸協議,所有的WWW文件都必須遵守這個標準。
HTTP是一個基於TCP/IP通信協議來傳遞數據(HTML 文件, 圖片文件, 查詢結果等)
請求:客戶端發送給服務器端的數據
響應:服務器端發送給客戶端的數據

請求部分

請求基本結構

一個完整的由客戶端發送給服務器的HTTP請求中包含以下的完整數據:
1.請求行:請求方式、資源路徑、使用的協議以及版本號GET/monkey.html HTTP/1.1
2.多個請求頭:對客戶端環境描述、客戶端請求的主機地址等信息
Accept - - 瀏覽器可接收的MIME類型,即文件內容類型
Accept-Charset - - 告知服務器客戶端支持的字符集
Accept-Encoding - - 瀏覽器能夠進行解碼的數據編碼方式
Accept-Language - - 瀏覽器支持的語言
Connection - - 是否需要持久連接
Cookie - - 會話相關
Referer - - 當前頁面從哪個頁面訪問過來的
3.請求空行:空行,分隔
4.請求體:內容正文(GET沒有請求體,POST有請求體)

請求狀態碼

狀態碼 英文名稱 描述
200 OK 請求成功
400 Bad Request 客戶端請求的語法錯誤,服務器無法解析
404 Not Found 服務器無法根據客戶端的請求找到資源
500 Internal Server Error 服務器內部錯誤,無法完成請求
GET請求

  • 請求網址:http://localhost:8080/monkey.html?username=monkey&password=111
  • 請求參數信息全部在請求行中,請求的數據全部在瀏覽器的地址欄,在url後,請求的url長度有限制,不安全
  • 參數連接:資源?參數名=參數值&參數名=參數值&…
POST請求

  • 請求網址:http://localhost:8080/monkey.html
  • 請求參數在請求體中,請求的數據不會出現瀏覽器的地址欄,請求的url長度沒有限制,安全
GET和POST請求的區別

  • GET請求數據在瀏覽器的地址欄,而POST不會出現。故POST比GET更安全
  • POST請求的參數存放於請求體中,而GET存放於請求行中
  • GET請求URL長度有限制(上限2K),而POST沒有限制。文件上傳時使用POST方式
  • GET可以緩存,POST不能緩存
什麼情況下選擇GET或POST請求

  • 傳遞大量數據,上傳文件用POST
  • 機密信息用POST,因爲POST安全性比GET高
  • 僅僅是索取數據,使用GET
  • 增加、修改、刪除數據,使用POST

響應部分

響應基本結構

客戶端向服務器發送請求,服務器應當做出響應,將數據返回給客戶端
一個完整的由服務器發送給客戶端的HTTP響應中包含以下的完整數據:
1.響應行:HTTP協議版本、狀態碼、狀態英文名 如HTTP/1.1 200 OK
2.多個響應頭:對服務器的描述、對返回數據的描述(以下只舉例部分)
Location - -
Server - - 服務器名稱
Content-Encoding - - web服務器支持返回內容壓縮編碼類型
Content-Type - - 服務器告訴客戶端本次響應體數據格式以及編碼格式,text/html;charset=UTF-8
Transfer-Encoding - - 文件傳輸編碼
Refresh - - 定時刷新
Set-Cookie - - 設置HTTP Cookie
3.響應空行:空行
4.響應體:傳輸的數據

響應狀態碼

常見的200 - -成功;303 - - 重定向;400 - -Not Found,500 - - 服務器內部錯誤;405 - -沒有對應的doGET或者doPost方法
狀態碼 描述
1** 信息,服務器收到請求,需要客戶端繼續執行操作
2** 成功,操作被成功接收並處理
3** 重定向,需要進一步的操作以完成請求
4** 客戶端錯誤,請求包含語法錯誤或無法完成請求
5** 服務器錯誤,服務器在處理請求的過程中發生了錯誤

參考文檔:HTTP狀態碼參考文檔




Request和Response


Request部分

request體系結構

ServletRequest接口 - - 請求對象,封裝了獲取所有請求信息,如請求行、請求頭、請求實體
HttpServletRequest接口 - - 繼承了 ServletRequest接口,用於處理HTTP協議請求的方法

在這裏插入圖片描述

HttpServletRequest常用方法

獲取請求行數據 GET /MyItems/demo2?username=monkey HTTP/1.1

  • String getMethod() - - 返回請求方式(GET/POST)
  • String getContextPath() - - 返回虛擬目錄,如/MyItems
  • String getServletPath() - - 返回servlet的路徑,如/demo2
  • String getQueryString() - - 返回get方式請求參數,如
  • String getRequestURI() - - 返回請求行中資源名字 username=monkey
  • String getRequestURI() - - 返回請求URI,如/MyItems/demo2,URI(統一資源標識符,範圍比URL大)
  • StringBuffer getRequestURL() - - 返回請求URL,如http://localhost/MyItems/demo2 ,URL(統一資源定位符)
  • String getProtocol() - - 返回協議版本,如HTTP/1.1
  • String getRemoteAddr() - - 返回請求服務器的客戶端IP地址

獲取請求頭

  • String getHeader(String name) - - 根據指定的請求頭獲取對應的請求頭值,如Host、Connection、User-Agent等等

獲取請求體數據(注:只有POST請求方式纔有請求體)
1.先獲取流對象

  • BufferedReader getReader() - - 獲取字符輸入流,只能操作字符數據
  • ServletInputStream getInputStream() - - 獲取字節輸入流,可以操作所有類型數據(可用於文件上傳)

2.再從流對象中取數據
例如,從登陸表單中獲取數據,返回username=monkey&password=111

/*POST or GET*/
 BufferedReader br = request.getReader();
 String line = null;
 while((line = br.readLine())!= null){
     System.out.println(line);
 }

獲取請求參數(GET和POST都能使用)

  • String getParameter(String name) - - 根據參數名稱獲取對應參數值,如傳username獲取值monkey
  • String[] getParameterValues(String name) - - 根據參數名稱獲取該參數的多個值,返回的是數組,一般是複選框
  • Enumeration getParameterNames() - - 獲取所有請求參數的名稱,如username、password、age等等,返回枚舉類型
  • Map< Sting ,String[]> getParameterMap() - - 返回請求參數組成的Map集合,即鍵值對

解決中文亂碼問題

在這裏插入圖片描述

//設置流的編碼
request.setCharacterEncoding("utf-8");

案例:獲取用戶提交的內容

<body>
  <form action="/demo6" method="post">
      用戶名:<input type="text" name="username"><br>
      密碼:<input type="password" name="password"><br>
      愛好:<input type="checkbox" name="hobby" value="逛街">逛街
      <input type="checkbox" name="hobby" value="蹦迪">蹦迪
      <input type="checkbox" name="hobby" value="購物">購物
      <input type="checkbox" name="hobby" value="遊戲">遊戲
      <br>
      <input type="submit" value="註冊">
</form>
</body>
public class RequestDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        String name = request.getParameter("username");
        String password = request.getParameter("password");
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("用戶名:"+name);
        System.out.println("密碼:"+password);
        System.out.print("愛好:");
        for(int i = 0;i < hobbies.length;i++){
            System.out.print(hobbies[i]+" ");
        }
        System.out.println();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}
請求轉發

一種在服務器內部的資源跳轉方式,從Servlet1請求轉發到Servlet2,Servlet完成一部分功能再跳轉到Servlet2繼續完成Servlet1不能完成的功能

 request.getRequestDispatcher(String Path).forward(request,response);
 //
 參數:
 Path - - 表示跳轉的目標資源路徑,不能是當前服務器以外的資源路徑,如百度,csdn等等
/*瀏覽器這裏是GET請求,但是我在GET裏面調用POST封裝請求和響應對象,最終是由POST輸出*/
/*從RequestDemo1請求轉發到RequestDemo2*/
@WebServlet("/demo7")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("這裏是request的POST demo7");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}

@WebServlet("/demo6")
public class RequestDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo6這裏執行了");
        request.getRequestDispatcher("/demo7").forward(request,response);
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

轉發特點 - - forward

  • 瀏覽器地址欄路徑不發生變化
  • 只能轉發到當前服務器下的資源路徑,不能是當前服務器以外的資源,如百度、csdn等
  • 請求轉發只發送一個請求
共享數據

域對象 - - 一個有作用範圍的對象,可以在範圍內共享數據
request域 - - 代表一次請求的範圍
作用域對象如何共享數據?

  • void setAttribute(String name,Object obj) - - 設置作用域中的共享數據
  • Object getAttribute(String name) - - 通過鍵獲取值
  • removeAttribute(String name) - - 通過移除鍵值對
/*RequestDemo1和RequestDemo2 設置和獲取 共享數據 */
/*輸出obj的結果爲monkey*/
@WebServlet("/demo7")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object obj = req.getAttribute("v");
        System.out.println(obj);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}

@WebServlet("/demo6")
public class RequestDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute("v","monkey");
        request.getRequestDispatcher("/demo7").forward(request,response);
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}



Response部分


HttpServletResponse常用方法

ServletResponse接口 - - 響應對象,封裝了獲取所有響應消息(狀態行,響應頭,請求實體)的方法
HttpServletResponse接口 - - 繼承了ServletResponse接口,處理HTTP協議響應的方法

設置響應消息—普通方法

  • setHeader(int sc) - - 設置狀態碼
  • setHeader(String name,String value) - - 設置響應頭

設置響應體
獲取輸出流(字符輸出流or字節輸出流)->使用輸出流,將數據輸出到客戶端瀏覽器
字符輸出流 - - PrintWriter getWriter()
該方法獲取的字符輸出流對象爲PrintWriter類型,可直接輸出字符文本內容,若想要輸出內容全爲字符文本的網頁文檔,可使用getWriter()方法

字節輸出流 - - ServletOutputStream getOutputStream()
該方法獲取的字節輸出流對象爲ServletOutputStream類型,是OutputStream的子類,可以直接輸出字節數組中的二進制數據。若想要輸出二進制格式的響應正文,就使用getOutputStream()方法,如文件下載

/*使用字節輸出流來輸出純文本數據*/
 resp.setContentType("text/html;charset=utf-8");
 ServletOutputStream sos = resp.getOutputStream();//獲取字節輸出流
 sos.write("頭髮沒了哦".getBytes("utf-8"));//輸出純文本數據

注意不能同時使用PrintWriter和OutputStream,比如如下代碼會報錯

OutputStream os = response.getOutputStream();
os.write("monkey".getBytes());
PrintWriter out = response.getWriter();
out.println("cat");

中文亂碼問題解決

/*方式一
resp.setCharacterEncoding("utf-8");//獲取流對象之前,設置流的默認編碼:ISO-8859-1 設置爲其他的編碼格式
resp.setHeader("content-type","text/html;charset=utf-8"); //告知瀏覽器服務器發送消息體數據的編碼,建議瀏覽器使用該編碼解碼
PrintWriter pw = resp.getWriter();//獲取字符輸出流
pw.write("<h1>monkey<h1>"); 
pw.write("頭髮沒了哦");
*/
//方式二
resp.setContentType("text/html;charset=utf-8");

重定向

是一種資源跳轉方式

在這裏插入圖片描述
實現重定向

方法一:設置狀態碼+設置路徑

@WebServlet("/resDemo1")
public class ResponseDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo1執行了哦");
        resp.setStatus(302); //設置狀態碼
        resp.setHeader("location","/resDemo2"); //設置路徑
    }
}

@WebServlet("/resDemo2")
public class ResponseDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("訪問demo1,自動跳轉到這裏的demo2");
    }
}

方法二:使用直接的方法設置路徑

resp.sendRedirect("/resDemo2");

重定向的特點 - - redirect

  • 地址欄發生變化
  • 重定向可以訪問其他站點的資源,如百度、csdn等
  • 重定向是兩次請求,不能使用request對象共享數據

ServletContext

基本概述

ServletContext原理

  • ServletContext是在服務器,被所有客戶端共享
  • ServletContext是當web應用啓動時,自動創建
  • 當Web應用關閉/tomcat應用關閉/對Web應用reload時,都會造成ServletContext銷燬

ServletContext接口代表整個web應用,是Servlet中最大的接口,呈現了Web應用的Servlet視圖,獲得方法

ServletContext context1 = request.getServletContext();
ServletContext context2 = this.getServletContext();
ServletContext功能

1.獲取MIME類型:在互聯網通信過程中定義的一種文件數據類型,如text/html、image/jpeg
String getMimeType(String file) - - 獲取MIME類型

2.多個Servlet之間共享數據(域對象)
setAttribute(String name,Object object) - - 向ServletContext中存數據
getAttribute(String name) - - 從ServletContext中獲取數據
removeAttribute(String name) - - 從ServletContext中移除數據

/*兩類之間共享context變量*/

@WebServlet("/resDemo1")
public class ResponseDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        context.setAttribute("v","monkey");
    }
}

@WebServlet("/resDemo2")
public class ResponseDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        Object obj = context.getAttribute("v");
        System.out.println(obj);
    }
}

3.獲取當前WEB項目中指定的資源文件
getRealPath(String str) - - 獲取資源絕對路徑

//獲取ServletContext對象
ServletContext context = this.getServletContext();
/* 
'/'代表E:\JavaWeb\out\artifacts\JavaWeb_war_exploded下的文件
如果想要訪問WEB-INF下的文件,則路徑寫'/WEB-INF/other.html'
若要訪問src下的文件,則路徑寫'/WEB-INF/classes/other.txt'
 */
//讀取web項目文件下的文件
String realPath = context.getRealPath("/monkey.txt");
System.out.println(realPath);//E:\JavaWeb\out\artifacts\JavaWeb_war_exploded\monkey.txt
//讀取該文件的內容
BufferedReader br = new BufferedReader(new FileReader(realPath));
String MyContext = br.readLine();
System.out.println(MyContext);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章