- List item
- 掌握Servlet的执行原理和生命周期
- 掌握Servlet的体系结构,了解其他Servlet配置
- 掌握Servlet3.0注解配置
- 理解HTTP协议及HTTP请求和响应
- 熟练掌握Request和Response核心API
- 熟练掌握登陆案例
Servlet什么时候被创建?
默认情况下,第一次被访问时,Servlet被创建,可以配置执行Servlet的创建时机。
- 在
标签下配置 - 第一次被访问时创建:
的值为负数 - 在服务器启动时创建:
的值为0或正整数
- 第一次被访问时创建:
Servlet的init方法只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的,多个用户同时访问时可能存在线程安全问题。
- 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值
- 每次访问Servlet时,service方法都会被调用一次。
- Servlet被销毁时执行。服务器关闭时,Servlet被销毁
- 只有服务器正常关闭时,才会执行destroy方法。
- destroy方法在Servlet被销毁之前执行,一般用于释放资源
创建一个Servlet,理解Servlet的生命周期。
package com.bailiban.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class Demo2Servlet implements Servlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("我出生了...");
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("我响应请求了...");
}
@Override
public void destroy() {
System.out.println("我挂了... ");
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
}
1.2 Servlet3.0 注解配置
Servlet3.0开始支持注解配置,通过WebServlet注解来实现映射,web.xml不再是必需的组件。
步骤:
- 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
- 定义一个类,实现Servlet接口
- 复写方法
- 在类上使用@WebServlet注解,进行配置
- @WebServlet("资源路径")
下面是@WebServlet的源码实现
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface WebServlet {
String name() default "";//相当于
String[] value() default {};//代表urlPatterns()属性配置
String[] urlPatterns() default {};//相当于
int loadOnStartup() default -1;//相当于
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
1.3 Servlet体系结构
Servlet– 接口
|
GenericServlet – 抽象类
|
HttpServlet – 抽象类
-
GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
- 定义Servlet类时,可以继承GenericServlet,实现service()方法即可
package com.bailiban.servlet; import java.io.IOException; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; @WebServlet("/demo1") public class Demo1Servlet extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("继承 GenericServlet 方式 创建Servlet"); } } -
HttpServlet:对http协议的一种封装,简化操作 (我们一般使用这个)
- 定义类继承HttpServlet
- 复写doGet/doPost方法
package com.bailiban.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/demo2") public class Demo2Servlet extends HttpServlet { private static final long serialVersionUID = 1L; //如果请求方式为get执行该方法 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("get方式~~~~~"); } //如果请求方式为post执行该方法 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("post方式~~~~~"); } }
分别以继承GenericServlet和HttpServlet方式 创建Servlet。
二、HTTP协议 2.1 HTTP协议概念-
什么是协议
- 生活中协议:双方进行交流的一个标准 和约束
- 协议:协议的甲乙双方,就是客户端(浏览器)和服务器!理解成双方通信的格式!
-
HTTP概念:Hyper Text Transfer Protocol 超文本传输协议
- 传输协议:定义了,客户端和服务器端通信时,发送数据的格式
-
HTTP协议特点:
- 基于TCP/IP的高级协议
- 默认端口号:80
3. 基于请求/响应模型的:一次请求对应一次响应
4. 无状态的:每次请求之间相互独立,不能交互数据
-
历史版本:
* 1.0:每一次请求响应都会建立新的连接
* 1.1:复用连接
http协议是一个重要的协议,他是贯穿整合B/S架构的核心协议。因此学习http协议的时候一定要从请求和响应两个角度思考。
2.2 HTTP 请求注意方向性(请求:浏览器->服务器;响应:服务器->浏览器)。
客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求。
一个完整的HTTP请求包括如下内容:
-
请求行:
请求方式 请求url 请求协议/版本
-
请求头:客户端浏览器告诉服务器一些信息
请求头名称: 请求头值
-
请求空行:
空行,就是用于分割POST请求的请求头,和请求体的。
-
请求体(正文):
封装POST请求消息的请求参数的
请求字符串格式:
POST /servlet_demo/demo2 HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.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 Content-Type: application/x-www-form-urlencoded Content-Length: 16 Origin: http://localhost:8080 Connection: keep-alive Referer: http://localhost:8080/servlet_demo/demo2.html Upgrade-Insecure-Requests: 1 username=wangcai2.3 HTTP请求方式
请求行中的包含请求方式信息,请求方式有:
POST、GET、HEAD、OPTIONS、DELETE、TRACE、PUT
常用的有: GET、 POST
2.3.1 GET请求方式- 通过浏览器地址栏访问的方式
- 使用超链接方式
- 使用js中的location.href 方式
- 表单的方式设置method=“get”
特点:
- 数据直接跟在URL地址后面明文显示的格式 ?key1=value1&key2=value2…
- 请求的url长度有限制的
- 安全性较低,数据可以直接在地址栏看到
- 将表单的提交方式设为method=“post”
特点:
- 数据是隐藏在请求体里面的不是明文的也是key/value的形式
- 数据大小没有限制
- 安全性高
下面的表格比较了两种 HTTP 方法:GET 和 POST。
| GET | POST | |
|---|---|---|
| 后退按钮/刷新 | 无害 | 数据会被重新提交(浏览器应该告知用户数据会被重新提交)。 |
| 书签 | 可收藏为书签 | 不可收藏为书签 |
| 缓存 | 能被缓存 | 不能缓存 |
| 编码类型 | application/x-www-form-urlencoded | application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
| 历史 | 参数保留在浏览器历史中。 | 参数不会保存在浏览器历史中。 |
| 对数据长度的限制 | 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 | 无限制。 |
| 对数据类型的限制 | 只允许 ASCII 字符。 | 没有限制。也允许二进制数据。 |
| 安全性 | 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! | POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
| 可见性 | 数据在 URL 中对所有人都是可见的。 | 数据不会显示在 URL 中。 |
一个HTTP响应代表服务器向客户端回送的数据,它包括:
-
响应行:
组成:协议/版本、响应状态码、状态码描述
响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
-
状态码都是3位数字
-
分类:
- 1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
- 2xx:成功。代表:200
- 3xx:重定向。代表:302(重定向),304(访问缓存)
- 4xx:客户端错误。代表:404(请求路径没有对应的资源) ,405:请求方式没有对应的doXxx方法
- 5xx:服务器端错误。代表:500(服务器内部出现异常)
-
-
响应头:
-
格式:头名称: 值
-
常见的响应头:
- Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
- Content-disposition:服务器告诉客户端以什么格式打开响应体数据
- in-line:默认值,在当前页面内打开
- attachment;filename=xxx:以附件形式打开响应体。文件下载
-
-
响应空行
-
响应体:传输的数据
响应字符串格式
HTTP/1.1 200 Accept-Ranges: bytes ETag: W/"309-1594050856290" Last-Modified: Mon, 06 Jul 2020 15:54:16 GMT Content-Type: text/html Content-Length: 309 Date: Mon, 06 Jul 2020 16:02:39 GMT三、Request 3.1 Request概述 request对象和response对象的原理demo2
- request和response对象是由服务器创建的。我们来使用它们
- request对象是来获取请求消息,response对象是来设置响应消息
ServletRequest–接口
| 继承
HttpServletRequest–接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)
POST /servlet_demo/demo2 HTTP/1.1
方法:
1. 获取请求方式 : `String getMethod()` 2. 获取虚拟目录:`/servlet_demo` * `String getContextPath()` 3. 获取Servlet路径:`/demo2` * `String getServletPath()` 4. 获取get方式请求参数:`name=zhangsan` * `String getQueryString()` 5. 获取请求URI: * `String getRequestURI()`:`/servlet_demo/demo2` * `StringBuffer getRequestURL()` : `http://localhost/servlet_demo/demo2`
获取请求头数据URL:统一资源定位符 :http://localhost/servlet_demo/demo2 中华人民共和国
URI:统一资源标识符 : /servlet_demo/demo2 共和国
- 方法:
- 通过请求头的名称获取请求头的值: String getHeader(String name)
- 获取所有的请求头名称: Enumeration
getHeaderNames()
-
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
-
步骤:
-
获取流对象
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
在文件上传知识点后讲解
-
再从流对象中拿数据
-
1. String getParameter(String name):根据参数名称获取参数值 username=zs&password=123 2. String[] getParameterValues(String name):根据参数名称获取参数值的数组 hobby=xx&hobby=game 3. EnumerationgetParameterNames():获取所有请求的参数名称 4. Map getParameterMap():获取所有参数的map集合
3.2.3 请求转发 forward(重点)中文乱码问题:
get方式:tomcat 8 已经将get方式乱码问题解决了
post方式:会乱码
解决:在获取参数前,设置request的编码request.setCharacterEncoding(“utf-8”);
一种在服务器内部的资源跳转方式
-
步骤
- 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
- 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
-
特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中。
- 转发是一次请求
3.2.4 共享数据(重点)请求转发的应用场景:MVC设计模式
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
- void setAttribute(String name,Object obj):存储数据
- Object getAttitude(String name):通过键获取值
- void removeAttribute(String name):通过键移除键值对
HTTP/1.1 200
设置状态码:setStatus(int sc)
设置响应头- 方法:setHeader(String name, String value)
-
步骤:
- 获取字符输出流:PrintWriter out= response.getWriter();
- 输出数据:out.write(数据);
-
乱码问题:
PrintWriter out= response.getWriter();获取的流的默认编码是ISO-8859-1
告诉浏览器响应体使用的编码和响应的数据类型:response.setContentType("text/html;charset=utf-8");
资源跳转的方式
- 代码实现
- response.sendRedirect(跳转地址);
- 特点:
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求。不能使用request对象来共享数据
- 重定向是两次请求,转发是一次请求。
- 重定向浏览器地址栏发生变化,转发浏览器地址栏路径不发生变化
- 重定向可以访问其他服务器的资源 ,转发只能转发到当前服务器内部资源中
路径分类
-
相对路径:通过相对路径不可以确定唯一资源
- 如:./index.html
- 不以/开头,以.开头路径
- 规则:找到当前资源和目标资源之间的相对位置关系
- ./:当前目录
- ../:上一级目录
-
绝对路径:通过绝对路径可以确定唯一资源
- 如:http://localhost/day15/responseDemo2
- 以/开头的路径
- 规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
- 建议虚拟目录动态获取:request.getContextPath()
- ,
- 给服务器使用:不需要加虚拟目录
- 转发路径
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
完成用户登录综合案例
需求:
-
编写login.html登录页面
-
用户输入用户名和密码,将数据提交到LoginServlet
-
在LoginServlet中接收用户名和密码
-
登录成功重定向到SuccessServlet 显示欢迎信息
-
登录失败将错误信息转发到ErrorServlet 显示
-



