servlet&&HTTP協(xié)議&&Request對象學(xué)習(xí)
1.servlet 的體系結(jié)構(gòu)和介紹
Servlet
||
GenericServlet:將除service方法外的其余方法默認空實現(xiàn)召夹,只將service方法作為抽象(在正式開發(fā)的時候跪楞,我們不會使用這種方法),在使用的時候,直接直接定義一個類繼承g(shù)enericservlet類即可
||
HttpServlet:對http協(xié)議的一種封裝类少,簡化操作
處理了一個判斷請求的功能缀匕,在以前使用的servlet中當一個訪問來后艺蝴,創(chuàng)建完service方法腿准,無論是get方法請求還是 post方式請求,都需要進行判斷才能使用滓鸠,因為這兩種方式是不同的雁乡,所以我們需要判斷,而HttpServlet就在內(nèi)部對這個進行
編寫糜俗,直接有doget,dopost方法踱稍,來響應(yīng)不同方式的請求。而我們一般只寫一個
在doget中調(diào)dopost悠抹,或者在dopost中調(diào)doget珠月;
2.servlet的相關(guān)配置
- 1.使用注釋,資源路徑可以有多個锌钮,也就是說使用不同的資源路徑桥温,創(chuàng)建同一個servlet,訪問同一個servlet
- 2.在WebServlet注釋的定義中梁丘,可以看出侵浸,urlPattern是使用數(shù)組進行定義的所以旺韭,使用大括號對資源路徑進行賦值
@WebServlet({"/demo4","/de4","/d4"})//* 使用這三個資源路徑都可以訪問到servlet資源路徑. - 3.路徑定義規(guī)則:的優(yōu)先級很低,使用之后掏觉,會優(yōu)先匹配別的資源路徑
1./xxx : / :所有的資源路徑都可以訪問到當前的servlet
2./xxx/xxx (目錄結(jié)構(gòu)) :/xxx/* :也可以使用通配符
:/user/demo :多級目錄
3.*.do(自定義后綴名) :demo.do
2.Http協(xié)議(Hyper Text Transfer Protocol)
- 概念:超文本傳輸協(xié)議
傳輸協(xié)議:定義了客戶端與服務(wù)器端通信的時候区端,請求消息和響應(yīng)消息的格式
-
http協(xié)議的特點
1,基于tcp/ip協(xié)議的高級協(xié)議澳腹,也就是說面向連接的织盼,安全的,協(xié)議酱塔,進行通信的時候需要進行三次握手沥邻。
2,默認端口號是:80羊娃。
3唐全,基于請求/響應(yīng)模型:一次請求對應(yīng)一次響應(yīng),不會出現(xiàn)一次請求多次響應(yīng)的情況蕊玷,也不可能是對個請求一個響應(yīng)邮利。
4,無狀態(tài)的:每次請求之間相互獨立垃帅,不能交互數(shù)據(jù)
抓包延届,百度網(wǎng)頁的每一個資源都是一次請求 - 歷史版本
1.0:每一次請求響應(yīng)都是建立新的連接
1.1:復(fù)用鏈接,將所有資源獲都傳輸成功后再斷開連接贸诚,但是每一個資源都是
基于請求/響應(yīng)的模式
- http請求/響應(yīng)消息數(shù)據(jù)格式(在使用瀏覽器方庭,開發(fā)者工具抓包的時候,瀏覽器太高級會導(dǎo)致我們?nèi)W(xué)習(xí)的時候很不便利赦颇,所以我們使用垃圾一點的瀏覽器二鳄,查看原始頭)
1.請求行:(請求方式 請求url 請求協(xié)議和版本赴涵,在瀏覽器中會用其他的方式顯示媒怯,但是內(nèi)容還是這個內(nèi)容)
如:GET /login.html?name=xzw http/1.1
請求方式
http協(xié)議有7種請求方式,而我們常見的方式有兩種髓窜,get扇苞,post方式
GET方式:
1,請求參數(shù)在請求行中寄纵,在url后 鳖敷,如:name=xzw
2,請求的url長度有限制
3程拭,不太安全(在url中可以之間看見參數(shù))
POST方式:
1定踱,請求參數(shù)在請求體中
2,請求的url長度沒有限制
3恃鞋,相對安全(在url中看不見參數(shù))
2崖媚,請求頭(鍵值對的形式存在亦歉,請求頭名稱,請求頭值)(就是客戶端瀏覽器發(fā)送給服務(wù)器的一些信息)
如:
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: Idea-9bab5137=3dd752db-249a-4508-851c-04dd5f28bc9e
Upgrade-Insecure-Requests: 1
If-Modified-Since: Sun, 26 Jan 2020 08:12:31 GMT
If-None-Match: W/"620-1580026351282"
Cache-Control: max-age=0
其中幾個常用的請求頭:
1.User-Agent:瀏覽器告訴服務(wù)器畅哑,我訪問你使用的瀏覽器版本信息肴楷,這個信息可以在服務(wù)器中獲取,然后根據(jù)這個信息解決服務(wù)器的兼容問題
2.accept:可以接受什么樣的文本
3.referer:告訴服務(wù)器荠呐,我當前的請求從哪里來赛蔫?
referer:http://localhost:8080/java_idea_request/input.html
作用:1.防盜鏈2.統(tǒng)計功能(判斷疊加)
說明:就是可以通過這個請求頭,去判斷當前請求是從哪個連接過來的泥张,可以防止盜鏈呵恢,和統(tǒng)計工作
3.請求空行:就是用來分隔請求頭和請求體的
4.請求體:封裝Post請求消息的請求參數(shù)
Tomcat服務(wù)器在請求和響應(yīng)是真正的過程
1.Tomcat服務(wù)器會根據(jù)請求的url資源路徑,創(chuàng)建對應(yīng)的servlet對象媚创。
2.Tomcat服務(wù)器會創(chuàng)建request和response對象瑰剃,request對象中會封裝請求消息數(shù)據(jù)。
3.Tomcat服務(wù)器將request對象和response對象傳遞給service方法筝野,并且調(diào)用service方法晌姚。
4.我們可以通過request對象獲取請求消息數(shù)據(jù),再通過response對象設(shè)置響應(yīng)信息數(shù)據(jù)
5.服務(wù)器在給瀏覽器做出響應(yīng)之前歇竟,從response對象中那程序員設(shè)置的響應(yīng)數(shù)據(jù)信息(也就是說挥唠,在瀏覽器還沒有接受到響應(yīng)的時候,是服務(wù)器先獲取到response中的數(shù)據(jù)焕议,在將數(shù)據(jù)響應(yīng)給瀏覽器)
(宝磨!就是說我以前認為的request對象就是請求,response對象就是響應(yīng)是不對的盅安,他們只是對請求和響應(yīng)的封裝)
- request&&response對象的原理:
1.request和response對象是服務(wù)器創(chuàng)建的唤锉,我們只是使用它
2.request對象是用來獲取請求信息的,而response對象是用來設(shè)置響應(yīng)消息的
1.request對象
1.request繼承體系結(jié)構(gòu)
ServletRequest(接口)
|| 繼承
HttpServletRequest(接口)
|| 實現(xiàn)
RequestFacade(tomcat對象):我們實際使用的對象就是RequestFacade對象
- RequestFacade對象在文檔中沒有别瞭,可以在tomcat的源碼中找到窿祥,也就是說這是tomcat對HttpServlet接口進行的實現(xiàn)
2.request對象的功能
- 1.獲取請求行信息
1,請求行信息包括:請求方式 請求url 請求協(xié)議和版本
2蝙寨,方法:
@WebServlet("/request_demo2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.獲取請求頭方法
String method = req.getMethod();
System.out.println("方法:"+method);
//2.獲取虛擬目錄V
String contextPath = req.getContextPath();
System.out.println("虛擬路徑:"+contextPath);
//3.獲取資源路徑
String servletPath = req.getServletPath();
System.out.println("資源路徑:"+servletPath);
//4.獲取get請求的請求參數(shù)
String queryString = req.getQueryString();
System.out.println("請求參數(shù)"+queryString);
//5.獲取請求參數(shù)url
String requestURI = req.getRequestURI();
StringBuffer requestURL = req.getRequestURL();
System.out.println("url:"+requestURL);
System.out.println("uri:"+requestURI);
//6.獲取協(xié)議和版本
String protocol = req.getProtocol();
System.out.println("協(xié)議和版本:"+protocol);
//7.獲取客戶機的ip地址
String remoteAddr = req.getRemoteAddr();
System.out.println("客戶機的ip地址"+remoteAddr);
}
(!):URL和URI的區(qū)別:URI的范圍更大
URL:統(tǒng)一資源定位符--http://localhost:8080/java_idea_request/request_demo2
中華人民共和國
URI :統(tǒng)一資源標識符--/java_idea_request/request_demo2
共和國
- 2.獲取請求頭信息
- 3.獲取請求體信息
- 2.獲取請求頭信息
1晒衩,請求頭信息 鍵值對的存在
2,方法:兩個方法比較重要
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.獲取所有的請求頭信息 Enumeration看做迭代器使用
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()){
String name = headerNames.nextElement();
//2.通過請求頭名稱獲取請求頭的值
String header = request.getHeader(name);
System.out.println(name+":"+header);
}
}
- 案例:瀏覽器兼容和盜鏈問題還有統(tǒng)計數(shù)據(jù)的功能
1墙歪,瀏覽器兼容的問題
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//案例一:瀏覽器兼容問題,就是要獲取User-agent的值,判斷他的包含那一種瀏覽器的名字
String user_agent = request.getHeader("User-agent");
if (user_agent!=null){
if (user_agent.contains("Chrome")){
System.out.println("谷歌瀏覽器");
}
else if (user_agent.contains("Firefox")){
System.out.println("火狐瀏覽器");
}
}else {
System.out.println("user_agent為空");
}
}
2,統(tǒng)計數(shù)據(jù)功能
public class RequestDemo5 extends HttpServlet {
private static int a=0;
private static int b=0;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//實現(xiàn)對百度和網(wǎng)易兩個網(wǎng)站的進入的訪問量統(tǒng)計
//1.獲取Referer信息,然后判斷獲取的Referer中的信息听系,判斷是否在其中包含所需要的數(shù)據(jù),進行疊加
String referer = request.getHeader("Referer");
if (referer!=null){
if (referer.contains("baidu")){
this.a++;
}else if(referer.contains("wangyi")){
this.b++;
}
System.out.println("百度訪問:"+this.a+"次");
System.out.println("網(wǎng)易訪問:"+this.b+"次");
}
}
3,防盜鏈
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.獲取Referer的值
String referer = request.getHeader("referer");
System.out.println(referer);
//2.判斷鏈接是否來自首頁
if (referer!=null){
if (referer.contains("java_idea_request")){
//正常播放
System.out.println("正常播放");
}else {
//請在優(yōu)酷首頁播放
System.out.println("請在優(yōu)酷首頁進入");
}
}
}
- 3.獲取請求體信息
請求體只有在Post請求方式虹菲,才會有請求體靠胜,在請求體中封裝了post請求的請求參數(shù)
獲取步驟:
1,獲取流對象,字符流或者是字節(jié)流
2浪漠,從流對象中獲取數(shù)據(jù)
方法:
public class RequsetDemo7 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.獲取字符流對象:getReader();
BufferedReader reader = request.getReader();//獲取字符流,獲取字符
//2.獲取字節(jié)流對象getInputStream();
// ServletInputStream inputStream = request.getInputStream();//獲取字節(jié)流,操作所有類型的文件
String str = null;
//2.獲取流對象中的數(shù)據(jù)
while((str=reader.readLine())!=null){
System.out.println(str);
}
}
- 3.request 對象的其余功能
1菠赚,獲取請求參數(shù),通用方法(以前的方法獲取的是一個字符串的形式郑藏,每一個鍵值對之間用&連接衡查,而且在使用的時候還要分成get方式和post方式)
方法
//1. 通用方式獲取請求參數(shù)
String username = request.getParameter("name");
String password = request.getParameter("password");
System.out.println("username:"+username);
System.out.println("password:"+password);
//2.根據(jù)參數(shù)名獲取參數(shù)數(shù)組
String[] hobbies = request.getParameterValues("hobby");
System.out.println("興趣是");
for (String hobby : hobbies) {
System.out.println(hobby);
}
//3.獲取所有參數(shù)名
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
String parameter_value = request.getParameter(name);
System.out.println(name+":"+parameter_value);
}
//4.獲取所有參數(shù)的集合
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> strings = parameterMap.keySet();
for (String string : strings) {
String[] values = parameterMap.get(string);
System.out.println(string);
for (String value : values) {
System.out.println(" "+value);
}
}
在使用的過程中,會出現(xiàn)中文亂碼的問題:
- get方式:tomcat8已經(jīng)將get方式的亂碼問題解決了
- post方式:會亂碼必盖,主要原因是底層使用流的方式獲取數(shù)據(jù)
解決方法:設(shè)置流的編碼拌牲,在獲取參數(shù)之前設(shè)置request的編碼
request.setCharacterEncoding("utf-8");
我么在使用的時候,無論是使用get方式還是post的方式都需要設(shè)置編碼
效果:
中文編碼正常
- 4.請求轉(zhuǎn)發(fā)
概念:一種在服務(wù)器內(nèi)部資源跳轉(zhuǎn)方式
Aservlet
||兩個內(nèi)部資源之間的跳轉(zhuǎn)方式
Bservlet
1.步驟:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo9的doGet方法調(diào)用成功");
//1.獲取轉(zhuǎn)發(fā)器對象歌粥,并使用它進行轉(zhuǎn)發(fā),請求路徑是在虛擬路徑下的
request.getRequestDispatcher("/requestDemo10").forward(request,response);
}
2塌忽,特點(面試題經(jīng)常與重定向之間進行比較)
1.瀏覽器的地址欄沒有發(fā)生變化
2.只能請求轉(zhuǎn)發(fā)到當前服務(wù)器的內(nèi)部資源中
3.轉(zhuǎn)發(fā)是一次請求(調(diào)用了請求路徑的service方法)
- 5.共享數(shù)據(jù):request域,只能在請求轉(zhuǎn)發(fā)中實現(xiàn)失驶,也就是說只能在服務(wù)器內(nèi)部資源中使用
域?qū)ο螅阂粋€有作用范圍的對象土居,可以在范圍內(nèi)共享數(shù)據(jù)
request域:代表一次請求的范圍,一般用于請求轉(zhuǎn)發(fā)的多個資源中嬉探,共享數(shù)據(jù)
方法(因為在請求轉(zhuǎn)發(fā)中擦耀,使用的都是當前請求的request對象,進行的請求轉(zhuǎn)發(fā)涩堤,所以一般用于請求轉(zhuǎn)發(fā)的多個資源中眷蜓,共享數(shù)據(jù))
//demo9
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo9的doGet方法調(diào)用成功");
//1.存儲數(shù)據(jù)
request.setAttribute("name","xzw");
//3.通過鍵值移除域中的數(shù)據(jù)
request.removeAttribute("name");
//1.獲取轉(zhuǎn)發(fā)器對象,并使用它進行轉(zhuǎn)發(fā),請求路徑是在虛擬路徑下的
request.getRequestDispatcher("/requestDemo10").forward(request,response);
}
//demo10
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("進入demo10......");
//2.獲取request域中的內(nèi)容
Object name = request.getAttribute("name");
if (name!=null){
System.out.println(name.toString());
}else {
System.out.println("對象為空,可能已經(jīng)移除");
}
}
移除鍵值對后
- 6.獲取servletcontext:
//獲取servletContext對象
ServletContext servletContext = request.getServletContext();
System.out.println("servletContext:"+servletContext);
//結(jié)果:
servletContext:org.apache.catalina.core.ApplicationContextFacade@5a1fec1b