> 文档中心 > Servlet | HTTP协议、模板方法设计模式

Servlet | HTTP协议、模板方法设计模式

目录

一:HTTP协议概述

二:HTTP协议实操

三:模板方法设计模式 


一:HTTP协议概述

  • 什么是协议?

    • 协议实际上是某些人,或者某些组织提前制定好的一套规范、一套标准。

  • 什么是HTTP协议?

    • HTTP协议:是W3C制定的一种超文本传输协议。(通信协议:发送消息的模板提前被制定好)

    • W3C:万维网联盟组织

      • 负责制定标准的,例如:HTTP HTML4.0 HTML5 XML DOM等规范都是W3C制定的。

      • 万维网之父:蒂姆·伯纳斯·李

    • 什么是超文本?

      • 超文本说的就是不是普通文本,比如流媒体:声音、视频、图片等。

      • HTTP协议支持:不但可以传送普通字符串,同样支持传递声音、视频、图片等流媒体信息。

    • 这种协议游走在B和S之间;B向S发数据要遵循HTTP协议,S向B发数据同样需要遵循HTTP协议;这样B和S才能解耦合。

    • 什么是解耦合?

      • B不依赖S,S也不依赖B。

    • B/S表示:B/S结构的系统(浏览器访问WEB服务器的系统)

    • 浏览器 向 WEB服务器发送数据,叫做:请求(request)

    • WEB服务器 向 浏览器发送数据,叫做:响应(response)

    • HTTP协议包括:

      • 请求协议

        • 浏览器 向 WEB服务器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。

      • 响应协议

        • WEB服务器 向 浏览器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。

        • HTTP协议就是提前制定好的一种消息模板。浏览器不依赖具体的服务器品牌,WEB服务器也不依赖具体的浏览器品牌。 

二:HTTP协议实操

定义两个类实现GenericServlet

package com.bjpowernode.javaweb.servlet;import javax.servlet.GenericServlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import java.io.IOException;import java.io.PrintWriter;public class GetServlet extends GenericServlet {    @Override    public void service(ServletRequest request, ServletResponse response)     throws ServletException, IOException { // 设置响应的类型 response.setContentType("text/html"); // 打印到浏览器上 PrintWriter out = response.getWriter(); // out.println() 是输出信息到浏览器,最终源代码中换行。 // (不是网页上有换行效果,网页上有换行效果必须使用
) out.println(""); out.println(""); out.println(" "); out.println(" from get servlet"); out.println(" "); out.println(" "); out.println("

from post servlet

"); out.println(" "); out.println(""); }}
package com.bjpowernode.javaweb.servlet;import javax.servlet.GenericServlet;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import java.io.IOException;import java.io.PrintWriter;public class PostServlet extends GenericServlet {    @Override    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { // 设置响应的类型 response.setContentType("text/html"); // 打印到浏览器上 PrintWriter out = response.getWriter(); // out.println() 是输出信息到浏览器,最终源代码中换行。 // (不是网页上有换行效果,网页上有换行效果必须使用
) out.println(""); out.println(""); out.println(" "); out.println(" from post servlet"); out.println(" "); out.println(" "); out.println("

from post servlet

"); out.println(" "); out.println(""); }}

 编写web.xml配置文件

     get com.bjpowernode.javaweb.servlet.GetServlet         get /getServlet         post com.bjpowernode.javaweb.servlet.PostServlet         post /postServlet    

编写一个index.html文件,里面定义两个表单:一个get请求的表单、一个post请求的表单

        http协议    

get请求

username
password

post请求

username
password

 

1、HTTP的请求协议(B --> S)

  • HTTP的请求协议包括:4部分

    • 请求

    • 请求头

    • 空白行

    • 请求体

HTTP请求协议的具体报文:GET请求

GET /servlet05/getServlet?username=jack&userpwd=123 HTTP/1.1   请求行Host: localhost:8080 请求头Connection: keep-aliveCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Sec-Fetch-Site: noneSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentAccept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9    空白行    请求体

HTTP请求协议的具体报文:POST请求

POST /servlet05/postServlet HTTP/1.1   请求行Host: localhost:8080     请求头Connection: keep-aliveContent-Length: 29Cache-Control: max-age=0Upgrade-Insecure-Requests: 1Origin: http://localhost:8080Content-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Sec-Fetch-Site: same-originSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentReferer: http://localhost:8080/servlet05/index.htmlAccept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9   空白行username=zhangsan&userpwd=123  请求体
  • 请求行包括三部分:

    • 第一部分:请求方式(7种)

      • trace

      • options

      • head

      • put

      • delete

      • post(常用)

      • get(常用)

    • 第二部分:URI

      • 什么是URI统一资源标识符。代表网络中某个资源的名字。但是通过URI是无法定位资源的

      • 什么是URL统一资源定位符。代表网络中某个资源,同时,通过URL是可以定位到该资源的

      • URI和URL什么关系,有什么区别?

        • URL是包括URI的

        • http://localhost:8080/servlet05/index.html 这是URL。

        • /servlet05/index.html 这是URI。

    • 第三部分:HTTP协议版本号

  • 请求头

    • 请求的主机

    • 主机的端口

    • 浏览器信息

    • 平台信息

    • cookie等信息

    • ....

  • 空白行

    • 空白行是用来区分“请求头”和“请求体”

  • 请求体

    • 向服务器发送的具体数据。

2、HTTP的响应协议(S --> B)

  • HTTP的响应协议包括:4部分

    • 状态行

    • 响应头

    • 空白行

    • 响应体

  • HTTP响应协议的具体报文:

HTTP/1.1 200 ok 状态行Content-Type: text/html;charset=UTF-8响应头Content-Length: 32Date: Sat, 05 Nov 2022 08:12:19 GMTKeep-Alive: timeout=20Connection: keep-alive  空白行 响应体     from post servlet         

from get servlet

  • 状态行由三部分组成:

    • 第一部分:协议版本号(HTTP/1.1)

    • 第二部分:状态码(HTTP协议中规定的响应状态号,不同的响应结果对应不同的号码)。

      • 200 表示请求响应成功,正常结束。

      • 404表示访问的资源不存在,通常是因为路径写错了,或者是路径写对了,但是服务器中对应的资源并没有启动成功。总之404错误是前端错误!

      • 405表示前端发送的请求方式与后端请求的处理方式不一致时发生,例如:

        • 前端是POST请求,后端的处理方式按照get方式进行处理时,发生405

      • 500表示服务器端的程序出现了异常。一般会认为是服务器端的错误导致的。

      • 以4开始的,一般是浏览器端的错误导致的。

      • 以5开始的,一般是服务器端的错误导致的。

    • 第三部分:状态的描述信息

      • ok 表示正常成功结束。

      • not found 表示资源找不到。

  • 响应头(了解):

    • 响应的内容类型

    • 响应的内容长度

    • 响应的时间

    • ....

  • 空白行:

    • 用来分隔“响应头”和“响应体”的。

  • 响应体:

    • 响应体就是响应的正文,这些内容是一个长的字符串,这个字符串被浏览器渲染,解释并执行,最终展示出效果。

3、怎么查看的协议内容?

使用chrome浏览器:F12。然后找到network,通过这个面板可以查看协议的具体内容。

4、怎么向服务器发送GET请求,怎么向服务器发送POST请求?  

  • 到目前为止,只有一种情况可以发送POST请求:使用form表单,并且form标签中的method属性值为:method="post"。

  • 其他所有情况一律都是get请求:

    • 在浏览器地址栏上直接输入URL,敲回车,属于get请求。

    • 在浏览器上直接点击超链接,属于get请求。

    • 使用form表单提交数据时,form标签中没有写method属性,默认就是get

    • 或者使用form的时候,form标签中method属性值为:method="get"

5、 GET请求和POST请求有什么区别?

  • get请求发送数据的时候,数据会挂在URI的后面,并且在URI后面添加一个“?”,"?"后面是数据。这样会导致发送的数据回显在浏览器的地址栏上。(get请求在“请求行”上发送数据

    • http://localhost:8080/servlet05/getServlet?username=zhangsan&userpwd=1111

  • post请求发送数据的时候,在请求体当中发送。不会回显到浏览器的地址栏上,也就是说post发送的数据,在浏览器地址栏上看不到。(post在“请求体”当中发送数据

  • get请求只能发送普通的字符串。并且发送的字符串长度有限制,不同的浏览器限制不同。

  • post请求可以发送任何类型的数据,包括普通字符串,流媒体等信息:视频、声音、图片,理论上没有长度限制

  • get请求无法发送大数据量,post请求可以发送大数据量。

  • get请求比较适合从服务器端获取数据,post请求比较适合向服务器端传送数据。

  • get请求是安全的。get请求是绝对安全的。为什么?因为get请求只是为了从服务器上获取数据,不会对服务器造成威胁。

  • post请求是危险的。为什么?因为post请求是向服务器提交数据,如果这些数据通过后门的方式进入到服务器当中,服务器是很危险的。另外post是为了提交数据,所以一般情况下拦截请求的时候,大部分会选择拦截(监听)post请求。

  • get请求支持缓存

    • 任何一个get请求最终的“响应结果”都会被浏览器缓存起来。

    • 在浏览器缓存当中:一个get请求的路径 对应 一个资源。

    • 实际上,你只要发送get请求,浏览器做的第一件事都是先从本地浏览器缓存中找,找不到的时候才会去服务器上获取。这种缓存机制目的是为了提高用户的体验。

    • 有没有这样一个需求:我们不希望get请求走缓存,怎么办?怎么避免走缓存?我希望每一次这个get请求都去服务器上找资源,我不想从本地浏览器的缓存中取。

      • 只要每一次get请求的请求路径不同即可。

      • 怎么解决?可以在路径的后面添加一个每时每刻都在变化的“时间戳”,这样,每一次的请求路径都不一样,浏览器就不走缓存了。

  • post请求不支持缓存。(POST是用来修改服务器端的资源的。)

    • post请求之后,服务器“响应的结果”不会被浏览器缓存起来。因为这个缓存没有意义。

6、GET请求和POST请求如何选择,什么时候使用GET请求,什么时候使用POST请求?

  • 怎么选择GET请求和POST请求呢?衡量标准是什么呢?

    • 看这个请求是想获取服务器端的数据,还是想向服务器发送数据。

    • 如果你是想从服务器上获取资源,建议使用GET请求,

    • 如果你这个请求是为了向服务器提交数据,建议使用POST请求。

  • 大部分的form表单提交,都是post方式,因为form表单中要填写大量的数据,这些数据是收集用户的信息,一般是需要传给服务器,服务器将这些数据保存/修改等。

  • 如果表单中有敏感信息,还是建议适用post请求,因为get请求会回显敏感信息到浏览器地址栏上。(例如:密码信息)

  • 做文件上传,一定是post请求,要传的数据不是普通文本。

  • 其他情况都可以使用get请求。

7、不管是get请求还是post请求,发送的请求数据格式是完全相同的,只不过位置不同,格式都是统一的

  • 格式:name=value&name=value&name=value&name=value

  • name是什么?

    • 以form表单为例:form表单中输入域input标签的name属性。

  • value是什么?

    • 以form表单为例:form表单中输入域input标签的value属性。

三:模板方法设计模式 

  • 什么是设计模式?

    • 某个问题的固定的解决方案。(可以被重复使用。)

  • 有哪些设计模式?

    • GoF设计模式:通常我们所说的23种设计模式。(Gang of Four:4人组提出的设计模式)

      • 单例模式

      • 工厂模式

      • 代理模式

      • 门面模式

      • 责任链设计模式

      • 观察者模式

      • 模板方法设计模式

      • .....

    • JavaEE设计模式:

      • DAO

      • DTO

      • VO

      • PO

      • pojo

      • ....

    • ....

  • 什么是模板方法设计模式?

    • 在模板类的模板方法当中定义核心算法骨架,具体的实现步骤可以延迟到子类当中完成。

    • 模板类通常是一个抽象类模板类当中的模板方法定义核心算法,这个方法通常是final的(但也可以不是final的)

    • 模板类当中的抽象方法就是不确定实现的方法,这个不确定怎么实现的事交给子类去做。

例1:定义两个Student类和Teacher类,其它方法都相同,只有doSome()方法不同

存在的问题:

        第一:算法没有得到重复的使用。
        第二:代码没有得到复用。

Student类

package com.bjpowernode.template1;public class Student {    //这个方法描述学生的一天  public void day(){ // 和Teacher的算法相同。 qiChuang(); xiShu(); chiZaoCan(); doSome(); chiWanFan(); shuiJiao();    }    public void qiChuang(){ System.out.println("起床");    }    public void xiShu(){ System.out.println("洗漱");    }    public void chiZaoCan(){ System.out.println("吃早餐");    }    // 只有doSome()方法不同    public void doSome(){ System.out.println("学生上学,学习");    }    public void chiWanFan(){ System.out.println("吃晚饭");    }    public void shuiJiao(){ System.out.println("睡觉");    }}

Teacher类 

package com.bjpowernode.template1;public class Teacher { // 这个方法描述老师的一天  public void day(){ // 和Student的算法相同。 qiChuang(); xiShu(); chiZaoCan(); doSome(); chiWanFan(); shuiJiao();    }    public void qiChuang(){ System.out.println("起床");    }    public void xiShu(){ System.out.println("洗漱");    }    public void chiZaoCan(){ System.out.println("吃早餐");    }    // 只有这个方法不同    public void doSome(){ System.out.println("老师正在课堂上授课,教授学生知识");    }    public void chiWanFan(){ System.out.println("吃晚饭");    }    public void shuiJiao(){ System.out.println("睡觉");    }}

例2:使用模板方法设计模式进行优化

 Teacher和Student都是Person
        第一:Person就是模板方法设计模式当中的模板类。
        第二: day()方法就是模板方法设计模式当中的模板方法。

模板类Person类

package com.bjpowernode.template2;public abstract class Person { // 模板类通常是抽象类。    // 模板方法    // 添加了final之后,这个方法无法被覆盖,这样核心的算法也可以得到保护。    // 模板方法定义核心的算法骨架,具体的实现步骤可以延迟到子类当中去实现。    // 核心算法一方面是得到了保护,不能被改变。另外一方面就是算法得到了重复使用。    // 另外代码也得到了复用,因为算法中某些步骤的代码是固定的。这些固定的代码不会随着子类的变化而变换,这一部分代码可以写到模板类当中。    public final void day(){ // 第一步 qiChuang(); // 第二步 xiShu(); // 第三步 chiZaoCan(); // 第四步 doSome(); // 第五步 chiWanFan(); // 第六步 shuiJiao();    }    // 其中的某些步骤,不会随着子类的变化而变化,这些代码可以写到父类中,得到代码复用。    public void qiChuang(){ System.out.println("起床");    }    public void xiShu(){ System.out.println("洗漱");    }    public void chiZaoCan(){ System.out.println("吃早餐");    }    // 写成抽象方法:这一步是要做,但是具体这一步怎么做,子类说了算。    public abstract void doSome();    public void chiWanFan(){ System.out.println("吃晚饭");    }    public void shuiJiao(){ System.out.println("睡觉");    }}

Student类继承Person类

package com.bjpowernode.template2;public class Student extends Person {    public void doSome(){ System.out.println("学生上学,学习");    }}

Teacher类继承Person类

package com.bjpowernode.template2;public class Teacher extends Person{    public void doSome(){ System.out.println("老师正在课堂上授课,教授学生知识");    }}

Test类进行测试调用

package com.bjpowernode.template2;public class Test {    public static void main(String[] args) { // 实用多态 Person p1 = new Teacher(); p1.day(); System.out.println("-----------------"); Person p2 = new Student(); p2.day();    }}