Servlet+HTTP+Request+Response+SevletContext+Cookie+Session大雜燴學習筆記


服務器軟件:可以接收用戶的請求,處理請求,做出響應。
在web服務器軟件中,可以部署web項目,讓瀏覽器可以訪問這些項目,中小型免費開源的JavaEE服務器,首選tomcat。
這裏就不講tomcat的安裝,可以直接在官網下載安裝。
一般將Tomcat集成到IDEA中,並且創建JavaEE的項目,部署項目。採用熱部署可以有更好的使用體驗。

Servlet

Servlet,可以拆分成server applet,概念上就是運行在服務器端的小程序。
實際上,Servlet是一個接口,定義了Java類被瀏覽器訪問到(tomcat識別)的規則。
在這裏插入圖片描述
想要使用接口,用戶就是要自定義實現類了。

自定義類的實現原理:
1.當服務器接受到客戶端瀏覽器的請求後,會解析請求URL路徑,獲取訪問的Servlet的資源路徑
2. 查找web.xml文件,是否有對應的<url-pattern>標籤體內容。
3. 如果有,則在找到對應的<servlet-class>全類名
4. tomcat會將字節碼文件加載進內存,並且創建其對象
5. 調用其方法
在這裏插入圖片描述
Servlet3.0以上就支持註解配置了,不需要在web.xml裏面寫一系列的代碼了。只需要在自定義實現類上加上註解@WebServlet(“資源路徑”)
在這裏插入圖片描述
那調用Servlet接口,然後複寫裏面的抽象方法,我們也總是隻複寫Service這一個方法,不方便。
這裏就引出了一個HttpServlet類,它是Servlet類的實現類。
那我們現在就可以通過繼承這個HttpServlet類來使用Servlet的方法了。
而且HttpServlet還有一個好處就是在服務器接收到請求的時候,提供了判斷請求方式的方法,常用的就是doPost()和doGet()。我們就不用自己去判斷是哪一種請求方式。在這裏插入圖片描述

HTTP

Hyper Text Transfer Protocol 超文本傳輸協議

這種傳輸協議定義了客戶端和服務器端通信時,發送數據的格式

特點
1.基於TCP/IP的高級協議
2. 默認端口號:80
3. 基於請求/響應模型的:一次請求對應一次響應
4. 無狀態的:每次請求之間相互獨立,不能交互數據

請求消息的數據格式
HTTP協議中的請求方式,常用的有GET和POST,先簡單講一下他們的區別:

GET
1.請求參數在請求行中,在url後。
2. 請求的url長度有限制的
3. 不太安全

POST
1.請求參數在請求體中
2. 請求的url長度沒有限制的
3. 相對安全

請求信息的數據格式
請求消息:客戶端發送給服務器端的數據

1.請求行:請求方式 請求url 請求協議/版本

2.請求頭:客戶端瀏覽器告訴服務器一些信息

3.請求空行:就是用於分割POST請求的請求頭,和請求體的。

4.請求體(正文):封裝POST請求消息的請求參數的

響應信息的數據格式
響應消息:服務器端發送給客戶端的數據

1.響應行:協議/版本 響應狀態碼 狀態碼描述

響應狀態碼:服務器告訴客戶端瀏覽器本次請求和響應的一個狀態。都是3位數字,分類如下:

1xx:服務器就收客戶端消息,但沒有接受完成,等待一段時間後,發送1xx多狀態碼

2xx:成功。代表:200

3xx:重定向。代表:302(重定向),304(訪問緩存)

4xx:客戶端錯誤。 例如: 404(請求路徑沒有對應的資源) 405:請求方式沒有對應的doXxx方法

5xx:服務器端錯誤。代表:500(服務器內部出現異常)

2.響應頭

格式:頭名稱: 值

常見的響應頭有以下兩種
Content-Type:服務器告訴客戶端本次響應體數據格式以及編碼格式
++++++++++分割線+++++++++++++
Content-disposition:服務器告訴客戶端以什麼格式打開響應體數據
常用的值:
in-line:默認值,在當前頁面內打開
attachment;filename=xxx:以附件形式打開響應體。文件下載

3.響應空行

4.響應體:傳輸的數據

Request

request對象和response對象的原理
1.request和response對象是由服務器創建的。我們來使用它們
2.request對象是來獲取請求消息,response對象是來設置響應消息
在這裏插入圖片描述

request功能
1.獲取請求消息數據
1.1 獲取請求行數據

package demo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/req_demo1")
public class Request_demo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取請求行數據: GET /Servlet_DEMO/req_demo1?username=123456 HTTP/1.1

        //獲取請求方式:GET
        String method = request.getMethod();
        System.out.println(method);
        //獲取虛擬目錄:/Servlet_DEMO
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //獲取資源文件(Servlet)路徑:/req_demo1
        String servletPath = request.getServletPath();
        System.out.println(servletPath);
        //獲取get方式的請求參數:username=123456
        String queryString = request.getQueryString();
        System.out.println(queryString);
        //獲取請求URI: /Servlet_DEMO/req_demo1
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        //獲取請求URL:http://localhost/Servlet_DEMO:war exploded/req_demo1
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURL);
        //獲取協議及版本:HTTP/1.1
        String protocol = request.getProtocol();
        System.out.println(protocol);
        //獲取客戶機的IP地址:
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);
    }
}

1.2 獲取請求頭數據

String getHeader(String name):通過請求頭的名稱獲取請求頭的值
Enumeration<String> getHeaderNames():獲取所有的請求頭名稱

demo

package demo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/request_demo2")
public class Request_demo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取所有請求頭名稱
        Enumeration<String> headerNames = request.getHeaderNames();
        while(headerNames.hasMoreElements()){
            String s = headerNames.nextElement();
            String header = request.getHeader(s);
            System.out.println(s+"----"+header);
        }
    }
}

package demo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/request_demo3")
public class Request_demo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取請求頭名稱:user-agent
        String header = request.getHeader("user-agent");
        if(header.contains("Chrome")){
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write("我是谷歌O ");
        }
    }
}

1.3 獲取請求體數據
只有POST請求方式,纔有請求體,在請求體中封裝了POST請求的請求參數

1.獲取流對象
BufferedReader getReader():獲取字符輸入流,只能操作字符數據
ServletInputStream getInputStream():獲取字節輸入流,可以操作所有類型數據
2.再從流對象中拿數據

demo

package demo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;

//獲取請求體數據
@WebServlet("/request_demo4")
public class Request_demo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        BufferedReader reader = request.getReader();
        String line=null;
        while((line=reader.readLine())!=null){
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(line);
        }
    }

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

    }
}

2.其他功能
2.1 獲取請求參數通用方式:不論get還是post請求方式都可以使用下列方法來獲取請求參數

demo

package demo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

/*
獲取請求參數通用方式:不論get還是post請求方式都可以使用下列方法來獲取請求參數
			1. String getParameter(String name):根據參數名稱獲取參數值    username=zs&password=123
			2. String[] getParameterValues(String name):根據參數名稱獲取參數值的數組  hobby=xx&hobby=game
			3. Enumeration<String> getParameterNames():獲取所有請求的參數名稱
			4. Map<String,String[]> getParameterMap():獲取所有參數的map集合
 */
@WebServlet("/request_demo5")
public class Request_demo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post中文亂碼解決,設置字符編碼爲utf-8
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        String[] parameterValues = request.getParameterValues("hobby");
//        for (String parameterValue : parameterValues) {
//            System.out.println(parameterValue);
//        }
        Enumeration<String> parameterNames = request.getParameterNames();
//        while(parameterNames.hasMoreElements()){
//            String s = parameterNames.nextElement();
//            String parameter = request.getParameter(s);
//            System.out.println(s+"=="+parameter);
//        }
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> strings = parameterMap.keySet();
        for (String string : strings) {
            String[] strings1 = parameterMap.get(string);
            System.out.println(string);
            for (String s : strings1) {
                System.out.println(s);
            }
            System.out.println("---------");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

2.2 請求轉發:一種在服務器內部的資源跳轉方式

步驟
1.通過request對象獲取請求轉發器對象:RequestDispatcher getRequestDispatcher(String path)
2.使用RequestDispatcher對象來進行轉發:forward(ServletRequest request, ServletResponse response)

特點:
1.瀏覽器地址欄路徑不發生變化
2.只能轉發到當前服務器內部資源中。
3.轉發是一次請求

2.3 共享數據

首先得說明一下域對象,之前我們說請求轉發是一次請求,就是一次請求可以波及到多個Servlet,這個影響的範圍就是request域。
在這裏插入圖片描述

域對象:一個有作用範圍的對象,可以在範圍內共享數據

request域:代表一次請求的範圍,一般用於請求轉發的多個資源中共享數據

方法
1.void setAttribute(String name,Object obj):存儲數據
2.Object getAttitude(String name):通過鍵獲取值
3.void removeAttribute(String name):通過鍵移除鍵值對

Response

功能:設置響應消息

1.設置響應行
格式爲:HTTP/1.1 200 ok
可以設置狀態碼:setStatus(int sc)

2.設置響應頭
setHeader(String name, String value)

3.設置響應體
步驟:
1.獲取輸出流,有兩種
字符輸出流:PrintWriter getWriter()
字節輸出流:ServletOutputStream getOutputStream()

2.使用輸出流,將數據輸出到客戶端瀏覽器

重定向
一種資源跳轉的方式
在這裏插入圖片描述

package demo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/response_demo1")
public class Response_demo1 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo1被訪問到了");
//        //設置響應狀態碼爲302,也就是重定向
//        resp.setStatus(302);
//        //設置重定向的頁面
//        resp.setHeader("location","/Servlet_Demo/response_demo2");
        //重定向的簡便寫法
        resp.sendRedirect("/Servlet_Demo/response_demo2");
    }

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

response如果回覆中文,會產生亂碼
在這裏插入圖片描述

package demo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/response_demo2")
public class Response_demo2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter.write("demo2又被訪問到了");
    }

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

forward 和 redirect 區別
重定向的特點:redirect

  1. 地址欄發生變化
  2. 重定向可以訪問其他站點(服務器)的資源
  3. 重定向是兩次請求。不能使用request對象來共享數據

轉發的特點:forward

  1. 轉發地址欄路徑不變
  2. 轉發只能訪問當前服務器下的資源
  3. 轉發是一次請求,可以使用request對象來共享數據

SevletContext

代表整個web應用,可以和程序的容器(服務器)來通信

可以通過兩種方法獲取對象
1.通過request對象獲取
request.getServletContext();

2.(推薦)通過HttpServlet獲取
this.getServletContext();

SevletContext功能如下

1.獲取MIME類型
MIME類型:在互聯網通信過程中定義的一種文件數據類型
格式: 大類型/小類型
例如:text/html 或 image/jpeg
String getMimeType(String file)
在獲取MIME類型後,我們就可以用來設置響應頭類型

2.域對象:共享數據
這個跟request域的概念差不多,方法一樣
但是ServletContext的範圍更大,是所有用戶所有請求的數據。request域的共享數據只在於一次請求的範圍

1.setAttribute(String name,Object value)
2.getAttribute(String name)
3.removeAttribute(String name)

3.獲取文件的真實(服務器)路徑

方法:String getRealPath(String path)  
String b = context.getRealPath("/b.txt");//web目錄下資源訪問
System.out.println(b);

String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目錄下的資源訪問
System.out.println(c);

String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目錄下的資源訪問
System.out.println(a);

會話技術

會話:一次會話中包含多次請求和響應。
一次會話:瀏覽器第一次給服務器資源發送請求,會話建立,直到有一方斷開爲止

功能:在一次會話的範圍內的多次請求間,共享數據

方式:
1.客戶端會話技術:Cookie
2.服務器端會話技術:Session

Cookie

概念:客戶端會話技術,將數據保存到客戶端

使用步驟:
1.創建Cookie對象,綁定數據
new Cookie(String name, String value)
2.發送Cookie對象
response.addCookie(Cookie cookie)
3.獲取Cookie,拿到數據
Cookie[] request.getCookies()

實現原理:基於響應頭set-cookie和請求頭cookie實現

服務器新建cookie對象,響應頭髮給客戶端。
客戶端收到cookie對象後,保存在客戶端,之後的請求頭會夾帶cookie信息,所以服務器可以在請求頭裏拿cookie數據

在這裏插入圖片描述
cookie的細節
1.一次可不可以發送多個cookie?
可以創建多個Cookie對象,使用response調用多次addCookie方法發送cookie即可。

2.cookie在瀏覽器中保存多長時間?
默認情況下,當瀏覽器關閉後,Cookie數據被銷燬
我們可以使用持久化存儲:

setMaxAge(int seconds)

seconds爲存活秒值
正數:將Cookie數據寫到硬盤的文件中。持久化存儲。並指定cookie存活時間,時間到後,cookie文件自動失效
負數:默認值
零:刪除cookie信息

3.cookie能不能存中文?
注意)在tomcat 8 之後,cookie支持中文數據。特殊字符還是不支持,建議使用URL編碼存儲,URL解碼解析

URL編碼:
String value=URLEncoder.encode(value,"utf-8");
URL解碼:
String value=URLDecoder.decode(value,"utf-8");

4.cookie共享問題?
4.1 假設在一個tomcat服務器中,部署了多個web項目,那麼在這些web項目中cookie能不能共享?
默認情況下cookie不能共享
setPath(String path):設置cookie的獲取範圍。默認情況下,設置當前的虛擬目錄
如果要共享,則可以將path設置爲"/"

4.2 不同的tomcat服務器間cookie共享問題?
setDomain(String path):如果設置一級域名相同,那麼多個服務器之間cookie可以共享
setDomain(".baidu.com"),那麼tieba.baidu.com和news.baidu.com中cookie可以共享

Cookie的特點和作用
特點
1.cookie存儲數據在客戶端瀏覽器
2.瀏覽器對於單個cookie 的大小有限制(4kb) 以及 對同一個域名下的總cookie數量也有限制(20個)

作用
1.cookie一般用於存儲少量的不太敏感的數據
2.在不登錄的情況下,完成服務器對客戶端的身份識別

Session

服務器端會話技術,在一次會話的多次請求間共享數據,將數據保存在服務器端的對象中。HttpSession

使用步驟:
1.獲取HttpSession對象:

HttpSession session = request.getSession();

2.使用HttpSession對象:

Object getAttribute(String name)  
void setAttribute(String name, Object value)
void removeAttribute(String name) 

原理:Session的實現是依賴於Cookie的。
客戶端請求頭會請求在服務器獲取session值,如果沒獲取到,那就創建一個新的session對象。如果獲取到了,那麼服務器會自動響應給客戶端一個sessionID。
接下來客戶端的請求頭就會夾帶這個sessionID去服務器內獲取session值。
在這裏插入圖片描述
細節

1.當客戶端關閉後,服務器不關閉,兩次獲取session是否爲同一個?
默認情況下。不是。
如果需要相同,則可以創建Cookie,鍵爲JSESSIONID,設置最大存活時間,讓cookie持久化保存。

Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);

2.客戶端不關閉,服務器關閉後,兩次獲取的session是同一個嗎?
不是同一個,但是要確保數據不丟失。tomcat自動完成以下工作

session的鈍化:
在服務器正常關閉之前,將session對象系列化到硬盤上
session的活化:(IDEA無法完成此功能,所以在IDEA中服務器一旦關閉在重啓就是新的session了)
在服務器啓動後,將session文件轉化爲內存中的session對象即可。

3.session什麼時候被銷燬?
1.服務器關閉
2.session對象調用invalidate() 。
3.session默認失效時間 30分鐘
選擇性配置修改

30

session的特點

1.session用於存儲一次會話的多次請求的數據,存在服務器端
2.session可以存儲任意類型,任意大小的數據

session與Cookie的區別:
1.session存儲數據在服務器端,Cookie在客戶端
2.session沒有數據大小限制,Cookie有
3.session數據安全,Cookie相對於不安全

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章