HTTP协议
1.介绍
- HTTP:超文本传输协议.
- HTTP协议是基于TCP/IP协议的
- 传输协议:客服端和服务器端的通信规则(握手协议)
2.HTTP协议的请求
2.1请求的组成部分
- 请求行:分三个部分,请求方式 请求路径 协议/版本
- 请求头:以键值对的形式存在
- 请求空行:普通的空行,用来区分请求头和请求体的
- 请求体:只有POST请求方式会将信息封装到请求体中,GET请求方式的信息在请求行中
2.2请求方式
3.HTTP协议的响应
响应的组成部分
- 响应行:响应方式 http/版本号 状态码 状态描述
- 响应头:以键值对的形式存在
- 响应空行:普通的空行,用来区分响应头和响应体的
- 响应体:将资源文件发给客服端浏览器进行解析
Servlet
servlet是运行在java服务器端的程序,用于接收和响应来自客户端基于http协议的请求.
1.实现servlet三种方式
1.1实现javax.servlet.Servlet接口,有一个核心方法service().
1.2继承GenericServlet抽象类,必须重写service方法,其他方法可选择重写.这种方法和http协议无关.
1.3继承HttpServlet抽象类(常用),需要重写doGet和doPost方法.该方法表示请求和响应都需要http协议相关.
2.实现方式之HttpServlet
实现步骤:
- 1.创建一个类继承HttpServlet
- 2.重写doGet和doPost方法
- 3.在web.xml中配置Servlet
- 4.部署并启动项目
- 5.通过浏览器测试
//在web.xml文件中的配置,不同实现有不同的配置
<servlet>
<servlet-name>ServletDemo</servlet-name>
<servlet-class>com.gul.servlet.ServletDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo</servlet-name>
<url-pattern>/ServletDemo</url-pattern>
</servlet-mapping>
3.servlet生命周期
出生 --> 工作 -->死亡
init()初始化方法
doGet or doPost 运行过程
destroy()销毁方法,只有正常关闭服务器才会执行.
对象只会创建一次,销毁一次,所以Servlet对象只有一个实例(单例模式).
4.线程安全问题
/*
Servlet线程安全
*/
public class ServletDemo04 extends HttpServlet{
//1.定义用户名成员变量
private String username = null;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//String username = null;
//synchronized (this) {
//2.获取用户名
username = req.getParameter("username");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.获取输出流对象
PrintWriter pw = resp.getWriter();
//4.响应给客户端浏览器
pw.print("welcome:" + username);
//5.关流
pw.close();
//}
}
一个浏览器代表一个线程,多个浏览器代表多个线程.当多个浏览器并发访问时,结果输出了最后一个浏览器访问的值.按理说我们期望每个浏览器查看的都是自己的用户名,而结果是浏览器中的数据混乱.所以我们认为Servlet是线程不安全的.
解决:定义类成员要谨慎.如果是共用的,并且只会才初始化时赋值,其他时间都是获取的话,那么是没有问题的.如果不是共用的,或者每次使用都有可能对其赋值,那么就要考虑线程安全问题了.可以将变量定义到doGet和doPost方法内或者使用同步功能即可.
5.默认servlet
默认 Servlet 是由服务器提供的一个 Servlet。它配置在 Tomcat 的 conf 目录中的 web.xml 中。
它的映射路径是/,我们在发送请求时,首先会在我们项目中的 web.xml 中查找映射配置,找到则执行。但是当找不到对应的 Servlet 路径时,就去找默认的 Servlet,由默认 Servlet 处理。所以,一切都是 Servlet。
6.servlet映射方式
- 第一种: /+具体类名;例如: /servletDeno
- 第二种: /固定格式/+通配符; 例如: /servlet/*
- 第三种: 通配符.固定格式结尾; 例如: *.do
越具体优先级越高.
7.Servlet多路径映射
可以配合映射的第二种[ /固定格式/* ]的方式实现多路径映射.
通过路径最后是/vip还是/vvip来判断打折的力度.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取该虚拟路径*/
String uri = req.getRequestURI();
System.out.println(uri);
System.out.println(this);
/*对虚拟路径的最后一个"/"后的字符进行截取*/
String type = uri.substring(uri.lastIndexOf("/"));
/*判断*/
int money = 1000;
if("/vip".equals(type)){
System.out.println("原价:" + money +"元,折后:" + (money*0.9));
}else if("/vvip".equals(type)){
System.out.println("原价:" + money +"元,折后:" + (money*0.5));
}
}
8.Servlet创建时机
1.第一次访问时创建
- 优势: 减少对服务器内存的浪费.提高服务器启动效率.
- 弊端: 如果有一些要在应用加载时就做的初始化操作无法完成.
2.服务器加载时创建
- 优势: 提前创建好对象,提高首次执行的效率.可以完成一些应用加载时要做的初始化操作.
- 弊端: 对服务器的内存占用较多,影响了服务器的启动效率.
3.修改Servlet常见时机:在web.xml的<servlet>标签中,添加<load-on-startup>标签.其<load-on-startup>中的值是正整数代表服务器加载时创建,值越小优先级越高.负整数或不写表示第一次访问时创建.
ServletConfig
1.介绍
- ServletConfig 是 Servlet 的配置参数对象,在 Servlet 的规范中,允许为每一个 Servlet 都提供一些初始化的配置。所以,每个 Servlet 都有一个自己的 ServletConfig。
- 作用:在 Servlet 的初始化时,把一些配置信息传递给 Servlet。
- 生命周期:和 Servlet 相同。
2.步骤
- 定义一个类,继承 HttpServlet。
- 在成员位置,声明一个 ServletConfig 对象。
- 重写 init 方法,并为 ServletConfig 对象赋值。
- 重写 doGet 和 doPost 方法。
- 在 web.xml 文件中进行配置。
- 在 doGet 方法中获取初始化参数。
- 部署并启动项目。
- 通过浏览器测试
3.配置方式
在<servlet>标签中,通过<init-param>标签来配置.有两个子标签.
<param-name>:代表初始化参数的key.
<param-value>:代表初始化参数的value.
<servlet>
<servlet-name>ServletConfigDemo</servlet-name>
<servlet-class>com.gul.servlet.ServletConfigDemo</servlet-class>
/*1*/
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
/*2*/
<init-param>
<param-name>desc</param-name>
<param-value>servletConfig args</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfigDemo</servlet-name>
<url-pattern>/ServletConfigDemo</url-pattern>
</servlet-mapping>
4.常用方法
//ServletConfig常用方法
//1.通过key获取value
String encoding = getInitParameter("encoding");
System.out.println(encoding);
String desc = getInitParameter("desc");
System.out.println(desc);
//2.获取所有key,以枚举方式展示
Enumeration<String> initParameterNames = getInitParameterNames();
while (initParameterNames.hasMoreElements()){
System.out.println(initParameterNames.nextElement());
}
//3.获取servlet名称
String servletName = getServletName();
System.out.println(servletName);
ServletContext
1.介绍
应用上下文对象,一个应用只有一个.
作用:可以获得应用的全局初始化参数和达到 Servlet 之间的数据共享。
生命周期:应用一加载则创建,应用被停止则销毁.
2.域对象
指的是对象的作用域.也就是作用范围.域对象可以实现数据的共享.不同作用范围的域对象,共享数据的能力也不一样.
在Servlet规范中,一共有四个域对象.ServletContext就是其中的一个.是web中最大的作用域.也叫application域.它可以实现整个应用之间的数据共享.
3.步骤
- 定义一个类,继承 HttpServlet。
- 重写 doGet 和 doPost 方法。
- 在 web.xml 文件中配置 Servlet 和 ServletContext。
- 获取 ServletContext 对象。
- 测试相关方法的使用。
- 部署并启动项目。
- 通过浏览器测试
4.配置全局初始化参数
ServletContext并不属于某个Servlet的配置,而是针对于整个应用的配置,也叫全局初始化参数.
在<web-app>标签中,通过<context-param>标签来配置.有两个子标签.
<param-name>:代表全局初始化参数的key
<param-value>:代表全局初始化参数的value.
<web-app>
<servlet>
<servlet-name>ServletContextDemo</servlet-name>
<servlet-class>com.itheima.servlet.ServletContextDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletContextDemo</servlet-name>
<url-pattern>/ServletContextDemo</url-pattern>
</servlet-mapping>
<!-- 键值对一-->
<context-param>
<param-name>globalEncoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
<!-- 键值对二-->
<context-param>
<param-name>globalDesc</param-name>
<param-value>This is ServletContext</param-value>
</context-param>
</web-app>
5.常用方法
ServletContext sc = getServletContext();
//ServletContext常用方法
//1.获取全局初始化参数
String ge = sc.getInitParameter("globalEncoding");
System.out.println(ge);
String gd = sc.getInitParameter("globalDesc");
System.out.println(gd);
//2.获取应用的虚拟路径
String contextPath = sc.getContextPath();
System.out.println(contextPath);
//3.根据虚拟路径得到应用的真实路径
String realPath = sc.getRealPath("/");
System.out.println(realPath);
//4.向作用域中添加数据
sc.setAttribute("element1","value1");
//5.在作用域中通过key得到value
Object value = sc.getAttribute("element1");
System.out.println(value);
//6.删除作用域中的键值对
sc.removeAttribute("element1");
注解开发Servlet
- 创建一个 web 项目。
- 定义一个类,继承 HttpServlet。
- 重写 doGet 和 doPost 方法。
- 在类上使用 @WebServlet 注解配置 Servlet。
- 部署并启动项目。
- 通过浏览器测试。
//注解,括号里是映射路径.注解开发不需要配置web.xml文件
@WebServlet("/AnnoServletDemo")
public class AnnoServletDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("注解开发...");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}