Java web核心
Servlet
Servlet介绍
- Servlet 是运行在 Java 服务器端的程序,用于接收和响应来自客户端基于HTTP 协议的请求。
- 如果想实现 Servlet 的功能,可以通过实现javax.servlet.Servlet接口或者继承它的实现类。
- 核心方法:service(),任何客户端的请求都会经过该方法。
执行流程
Servlet的关系视图
Servlet 实现方式
第一种
-
实现 Servlet 接口,实现所有的抽象方法。该方式支持最大程度的自定义。
第二种
-
继承 GenericServlet 抽象类,必须重写 service 方法,其他方法可选择重写。该方式让我们开发 Servlet 变得简单。 但是这种方式和HTTP 协议无关。
第三种 (重点)
-
继承 HttpServlet 抽象类,需要重写doGet 和 doPost 方法。该方式表示请求和响应都需要和HTTP 协议相关。
生命周期
-
对象的生命周期,就是对象从出生到死亡的过程。即:出生-> 活着 -> 死亡。官方说法是对象创建到销毁的过程!
-
出生:请求第一次到达Servlet 时,对象就创建出来,并且初始化成功。只出生一次,将对象放到内存中。
-
活着:服务器提供服务的整个过程中,该对象一直存在,每次浏览器对该servlet发起请求,都是执行service 方法。
-
死亡:当服务停止时,或者服务器宕机时,对象死亡。
注意:Servlet 对象只会创建一次,销毁一次。所以Servlet 对象只有一个实例。PS:如果一个对象实例在应用中是唯一的 存在,那么我们就称它为单例模式。
线程安全问题
-
由于 Servlet 采用的是单例模式,只会创建一个对象,该对象在多个线程之间是线程共享的。所以在定义该对象的属性时,我们要考虑线程安全。
-
解决:
1)如果定义的是属性,多个线程都是只读,没有重新赋值操作的话,不用考虑线程安全,存在多个线程对该属性有写操作,要考虑线程安全。
2)方法内定义的变量都是线程私有的,可以将变量 定义到 doGet 或 doPost 方法内
3)也可以加锁,实现同步功能即可,不推荐,效率太低。
不同映射的方式
第一种 (推荐)
-
具体名称的方式。访问的资源路径必须和映射配置完全相同。
第二种(了解)
-
/ 开头 + 通配符的方式。只要符合目录结构即可,不用考虑结尾是什么。
第三种
-
通配符 + 固定格式结尾的方式。只要符合固定结尾格式即可,不用考虑前面的路径。
注意:优先级问题。越是具体的优先级越高,越是模糊通用的优先级越低。第一种-> 第二种 -> 第三种
多映射的使用场景(例题了解)
-
我们可以给一个Servlet 配置多个访问映射,从而根据不同的请求路径来实现不同的功能。
-
场景分析:
1)如果访问的资源路径是/vip 商品价格打9折。
2)如果访问的资源路径是/vvip 商品价格打5折。
3)如果访问的资源路径是其他 商品价格不打折。
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
Servlet 多路径映射
*/
public class ServletDemo06 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int money = 1000;
//获取访问的资源路径
String name = req.getRequestURI();
name = name.substring(name.lastIndexOf("/"));
if("/vip".equals(name)) {
//如果访问资源路径是/vip 商品价格为9折
System.out.println("商品原价为:" + money + "。优惠后是:" + (money*0.9));
} else if("/vvip".equals(name)