Http&Servlet
一、HTTP协议介绍
(一)HTTP概念
Hypertext Transfer Protocol,HTTP超文本传输协议,是一个简单的请求-响应协议。
规定了客户端和服务器之间 传输数据的一种格式
(二)HTTP特点
基于TCP/IP的高级协议
默认端口号:80
基于请求/响应模型:一次请求对应一次响应
特点:
1.简单快速。客户端向服务器请求服务时,只需要传送请求方法和路径。
2.灵活。HTTP协议允许传送任意格式的数据。正在传输的类型由,content-type标明。
3.无连接。就是每个请求都建立一个连接,请求处理完毕并发送至客户端之后就断开连接。这样明显有其缺点,就是在需要连续发送请求时,需要为每一个请求单独的再次建立连接,很浪费时间和资源。于是在HTTP协议1.1版本之后引入了可持续连接,也就是再每一个请求处理完毕后,它不会立刻就断开连接,而是再等待一段时间,如果在此期间又有新的请求过来,那么等待时间刷新,如果没有,则等待时间完毕后,连接关闭。
4.无状态。是指协议对于每次请求的处理没有记忆能力,它不知道之前是否已经访问过,不保留访问痕迹。主要目的是为了保证数据传输的安全性。
(三)传输数据的特点
1、请求request
请求分为三部分:
请求行 : 请求行中,我们可以通过request对象的相应方法获取到比如协议名、服务名、端口号、项目名称、请求方式、参数列表等信息。
请求头 : 请求头是当前对用户发送的数据的描述信息。请求头信息在请求的时候不需要程序员手动添加,是浏览器发送的时候已经处理好的。
请求体 : 请求体就是请求中携带的数据,也就是我们需要获取的参数。
2、响应response
响应分为三部分:
响应行 : 响应行中包含协议和版本
响应头 : 服务器想要告诉浏览器 的一些信息。写法格式:头名称:值
响应体 : 服务器响应给浏览器的源码信息
二、Servlet详解
(一)Servlet概念
servlet 是运行在 Web 服务器中的小型 Java 程序。servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求
简单理解:
我们之前讲的JDBC技术是用来实现Java语言和数据库之间的连接技术,而现在又涉及到Java和HTML进行连接,此时可以由HTML做前台,java做后台进行连接,这时候就需要一个中间件(Servlet)。
(二)Servlet使用
1、准备工作
需求:写一个HTML页面将一个表单中的账号和密码传递到java类中并打印输出到控制台。
2、编写步骤
编写步骤: 1. 创建HTML页面并设计一个表单 2. 创建一个普通类, 并继承HTTPServlet抽象类, 并重写Service方法 3. 在web.xml文件中注册servlet, 作为前后台连接的中间件 4. 修改前台表单中action的请求地址 5. 通过浏览器输入对应的地址来访问测试
3、实现方式
- 创建HTML页面并设计一个表单
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 设计一个页面, 并设计表单 /项目名/访问地址 --> <form action="" method="post"> <p> 账号: <input type="text" name="username" id="username"> </p> <p> 密码: <input type="password" name="password" id="password"> </p> <p> <input type="submit" value="登录"> </p> </form> </body> </html>
- 创建一个普通类, 并继承HTTPServlet抽象类, 并重写Service方法
package com.ujiuye.servlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import java.io.IOException; //创建一个普通类, 让其普通类继承HttpServlet抽象类 public class LoginServlet extends HttpServlet { //并重写Service方法 @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println("账号为: " + username + " ==> 密码为: " + password); } }
- 在web.xml文件中注册servlet, 作为前后台连接的中间件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <!--注册servlet--> <servlet> <servlet-name>login</servlet-name><!--servlet名称--> <servlet-class>com.ujiuye.servlet.LoginServlet</servlet-class><!--全路径--> </servlet> <!--映射路径/虚拟路径--> <servlet-mapping> <servlet-name>login</servlet-name><!--servlet名称--> <url-pattern>/login</url-pattern><!--访问路径, 以 / 开头--> </servlet-mapping> </web-app>
- 修改前台表单中action的请求地址
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 设计一个页面, 并设计表单 /项目名/访问地址 --> <form action="login" method="post"> <p> 账号: <input type="text" name="username" id="username"> </p> <p> 密码: <input type="password" name="password" id="password"> </p> <p> <input type="submit" value="登录"> </p> </form> </body> </html>
- 通过浏览器输入对应的地址来访问测试
效果展示:
(三)Servlet原理
实现原理:
① 当服务器接收到客户端浏览器的请求后,先解析请求的url路径,获取访问Servelt的资源路径
② 查找项目的web.xml,根据资源路径匹配web.xml中的 <servlet-mapping>中的<url-pattern>
③ 如果没有匹配到报 404 如果匹配到了 根据<servlet-mapping>中的<servlet-name>
④ 再去匹配 <servlet>中的<servlet-name> 如果没有匹配到 404
⑤ 如果匹配到了执行<servlet> 中的<servlet-class> 从而以反射的方式访问到指定的Servlet,调用其方法
(四) Servlet生命周期
servlet生命周期:从创建到销毁的全过程。共分为三个阶段: 1、初始化 2、使用(提供服务) 3、销毁
案例演示:
- 创建一个Servlet重写其内部的三个方法init()、service()、destroy()
package com.ujiuye.servlet; import javax.servlet.*; import java.io.IOException; public class LifeCycleServlet implements Servlet { //初始化 @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("servlet初始化了..."); } @Override public ServletConfig getServletConfig() { return null; } //服务 @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("servlet中的service方法执行了...."); } @Override public String getServletInfo() { return null; } //销毁 @Override public void destroy() { System.out.println("servlet销毁了..."); } }
- 在web.xml文件中注册Servlet
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <!--注册servlet--> <servlet> <servlet-name>lifeCycle</servlet-name><!--servlet名称--> <servlet-class>com.ujiuye.servlet.LifeCycleServlet</servlet-class><!--全路径--> </servlet> <!--映射路径/虚拟路径--> <servlet-mapping> <servlet-name>lifeCycle</servlet-name><!--servlet名称--> <url-pattern>/lifeCycle</url-pattern><!--访问路径, 以 / 开头--> </servlet-mapping> </web-app>
- 测试查看Servlet生命周期
当我们启动tomcat服务器时,观察控制台并无打印消息,表示Servlet默认情况下在启动服务器时并未被创建。在浏览器地址栏中直接输入MyServlet的虚拟访问地址:
http://localhost:8080/day10_servlet/lifeCycle
此时观察控制台打印输出初始化与服务的相关信息,当多次访问该地址,发现服务方法被多次调用执行。
当我们关闭tomcat服务,会在控制台打印销毁方法的信息。
通过以上案例发现Servlet默认情况下是在第一次访问时被创建并初始化的,为了减少内存的压力,我们可否改变它的创建时机呢?
答案是肯定的。我们可以在web.xml文件中进行配置,使得Servlet在服务器启动时直接创建并初始化。
load-on-startup节点必须写在servlet节点的内部,且作为最后一个节点。取值必须是整数,如果是大于等于0的整数表示在服务器启动时就被创建并初始化,如果有多个Servlet设置了load-on-startup节点的值,那么值越小越优先执行;如果是负数则表示第一次被访问时创建并初始化,也就是默认情况,可以省略不写。
总结:
1、init()初始化阶段:默情况当第一次访问Servlet时,Servlet容器(tomcat)会加载Servlet,加载完成后,Servlet容器(tomcat)会创建一个Servlet实例并调用init()方法进行初始化;如果需要改变创建时机,只需要在web.xml文件中配置load-on-startup节点值为大于等于0的整数即可。init()方法只会执行一次,也说明一个Servlet只有一个实例,即单例模式。
2、service()服务阶段:当Servlet每被访问一次,service方法就会自动被调用一次,所以该方法可执行多次。
3、Destroy()销毁阶段:当关闭服务或资源重新加载时,destroy方法会被执行,这就标识着整个Servlet的生命周期到此结束。该方法仅被执行一次。只执行一次的阶段有 初始化阶段、销毁阶段。 因此 Servlet是单例的。
执行多次的阶段 服务阶段初始化的时机可以选择 (1.用到的时候再初始化 2.启动项目自动初始化)
5)Servlet路径多元化
问题 : 一个Servlet是否可以配置多个访问路径? 答案是可以的 url-pattern配置方式共有三种: 1. 完全路径匹配(一层路径/指定多层路径) :以 / 开始 例如: /hello , /hello1, /aa/hello2 2. 目录匹配(多种路径都可以访问 排除已经指定的路径) :以 / 开始 需要以 * 结束. 例如: /*(所有), /aaa/* (aaa目录下的所有), /aaa/bbb/* 3. 扩展名匹配(后缀名) :不能以 / 开始 以 * 开始的. 例如: *.do , *.action 注意: 错误的写法 : /*.do
案例演示
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <!--注册servlet--> <servlet> <servlet-name>hello</servlet-name><!--servlet名称--> <servlet-class>com.ujiuye.servlet.HelloServlet</servlet-class><!--全路径--> </servlet> <!--映射路径/虚拟路径--> <servlet-mapping> <servlet-name>hello</servlet-name><!--servlet名称--> <url-pattern>/hello</url-pattern><!--访问路径, 以 / 开头--> <!-- 目录匹配 --> <url-pattern>/aa/bb/cc</url-pattern> <url-pattern>/aa/bb/cc/dd/*</url-pattern> <!-- 扩展名匹配 --> <url-pattern>*.do</url-pattern> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app>
6)Servlet注解方式的使用
Java 注解(Annotation)又称 Java 标注,是 JDK1.5 引入的新特性。其主要作用是简化复杂的编码工作。Java 语言中的类、方法、变量、参数和包等都可以被标注,被标注的元素就具有了一些特定的功能。 Servlet的注解(@WebServlet)是Servlet3.0及以上版本支持的,主要目的是简化web.xml配置。 因此配置Servlet的方式有两种: 1.web.xml中配置 Servlet 这种写法比较麻烦。 代码比较多 2.通过注解 @WebServlet,配置了注解就不需要在web.xml中配置. /*注意 每一个Servlet只能选择其中一种方式配置 *
案例演示:
package com.ujiuye.servlet; 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; /*此注解配置相当于web.xml文件中url-pattern设置的访问路径*/ @WebServlet("/hello") public class HelloServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("注解版Servlet更加简明"); } }
注意事项:
注意:一个Servlet的配置可以使用注解,也可以使用web.xml文件,但二者不能共存,只能任选其一,否则会报错。