JavaWeb_day02_Tomcat&Servlet
1.Tomcat
1.1系统结构
- CS 结构:(Client Server) 客户端+服务器的方式
- BS 结构:(Browser Server) 浏览器+服务器的方式
1.2Tomcat 配置文件
-
主配置文件 server.xml
-
8080 端口:tomcat 服务默认端口号。访问 url 地址后必须手动写 :8080
-
80 端口:HTTP协议采用的端口号。访问 url 地址后不用写 :80
2.Servlet
2.1Servlet 介绍
- Servlet 是运行在Java服务器端的程序,用于接收和响应来自客户端基于 HTTP 协议的请求
2.2Servlet 执行过程
- 客户端浏览器 发起请求;
- Tomcat服务器 解析请求地址(URL);找到对应的应用;
- servlet_demo1 找到应用的web.xml
- web.xml 解析请求资源地址(URI)找到应用的资源
ServletDemo01 执行service方法,响应给客户端浏览器
2.3Servlet 实现方式
第一种
- 实现 Servlet 接口,实现所有的抽象方法。该方式支持最大程度的自定义。
第二种
- 继承 GenericServlet 抽象类,必须重写 service 方法,其他方法可选择重写。该方式让我们开发 Servlet变得简单。但是这种方式和 HTTP 协议无关。
第三种
- 继承 HttpServlet 抽象类,需要重写 doGet 和 doPost 方法。该方式表示请求和响应都需要和 HTTP 协议相关。
2.4Servlet 线程安全问题
-
由于 Servlet 采用的是单例模式,也就是整个应用中只有一个实例对象。所以我们需要分析这个唯一的实例对象中的类成员是否线程安全。
-
模拟用户登录功能来查看 Servlet 线程是否安全。
-
结论:一个浏览器代表一个线程,多个浏览器代表多个线程。按理说我们期望的应该是每个浏览器查看的都应该是自己的用户名。而现在的结果是浏览器中数据混乱。因此,我们可以认为 Servlet 是线程不安全的!
-
解决:定义类成员要谨慎。如果是共用的,并且只会在初始化时赋值,其他时间都是获取的话,那么是没问题的。如果不是共用的,或者每次使用都有可能对其赋值,那就要考虑线程安全问题了,可以将其定义到
doGet 或 doPost 方法内或者使用同步功能即可。
代码
package com.itheima.review;
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;
//模拟用户登录功能来查看 Servlet 线程是否安全
@WebServlet("/reviewDemo1")
public class reviewDemo1 extends HttpServlet {
private String username;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
synchronized (this) {
username = req.getParameter("username");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resp.getWriter().print("welcome" + username);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.5Servlet 映射方式
第一种
- 具体名称的方式。访问的资源路径必须和映射配置完全相同。
第二种
- / 开头 + 通配符的方式。只要符合目录结构即可,不用考虑结尾是什么。
第三种
- 通配符 + 固定格式结尾的方式。只要符合固定结尾格式即可,不用考虑前面的路径。
- 注意:优先级问题。越是具体的优先级越高,越是模糊通用的优先级越低。第一种 > 第二种 > 第三种。
2.6Servlet 多路径映射练习
- 我们可以给一个 Servlet 配置多个访问映射,从而根据不同的请求路径来实现不同的功能。
场景分析:
如果访问的资源路径是 /vip 商品价格打9折。
如果访问的资源路径是 /vvip 商品价格打5折。
如果访问的资源路径是其他 商品价格不打折。
代码
package com.itheima.review;
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;
import java.io.PrintWriter;
@WebServlet("/reviewDemo2/*")
public class reviewDemo2 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)) {
System.out.println((money * 0.9));
} else if ("/vvip".equals(name)) {
System.out.println(money * 0.5);
} else {
System.out.println(money);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.ServletConfig
3.1ServletConfig介绍
- ServletConfig 是 Servlet 的配置参数对象,在 Servlet 的规范中,允许为每一个 Servlet都提供一些初始化的配置。所以,每个 Servlet 都有一个自己的 ServletConfig
- 作用:在 Servlet 的初始化时,把一些配置信息传递给 Servlet
- 生命周期:和 Servlet 相同
3.2ServletConfig 配置方式
-
在
<servlet>
标签中,通过<init-param>
标签来配置。有两个子标签。 -
<param-name>
:代表初始化参数的 key。 -
<param-value>
:代表初始化参数的 value。
3.3ServletConfig 常用方法
-
String getInitParameter(String name) 根据参数名称获取参数的值
-
Enumeration getInitParameterNames() 获取所有参数名称的枚举
-
String getServletName() 获取Servlet的名称
-
ServletContext getServletContext() 获取ServletContext对象
3.4ServletConfig 实现步骤
-
定义一个类,继承 HttpServlet
-
在成员位置,声明一个 ServletConfig 对象
-
重写 init 方法,并为 ServletConfig 对象赋值
-
重写 doGet 和 doPost 方法
-
在 web.xml 文件中进行配置
-
在 doGet 方法中获取初始化参数
-
部署并启动项目
-
通过浏览器测试
代码
package com.itheima.review;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
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;
import java.util.Enumeration;
@WebServlet("/reviewDemo3")
public class reviewDemo3 extends HttpServlet {
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String encodingValue = config.getInitParameter("encoding");
System.out.println(encodingValue);
String servletName = config.getServletName();
System.out.println(servletName);
ServletContext servletContext = config.getServletContext();
System.out.println(servletContext);
Object username = servletContext.getAttribute("username");
System.out.println(username);
Enumeration<String> initParameterNames = config.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
String name = initParameterNames.nextElement();
String value = config.getInitParameter(name);
System.out.println(name + "..." + value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4.ServletContext
4.1ServletContext介绍
- ServletContext 是应用上下文对象(应用域对象)。每一个应用中只有一个 ServletContext 对象。
- 作用:可以获得应用的全局初始化参数和达到 Servlet 之间的数据共享。
- 生命周期:应用一加载则创建,应用被停止则销毁。
4.2ServletContext配置方式
- ServletContext 并不属于某个 Servlet 的配置,而是针对于整个应用的配置,也叫全局的初始化参数。
- 在
<web-app>
标签中,通过<context-param>
标签来配置。有两个子标签。 <param-name>
:代表全局初始化参数的 key。<param-value>
:代表全局初始化参数的 value。
4.3ServletContext 常用方法
-
String getInitParameter(String name) 根据名称获取全局配置的参数
-
String getContextPath() 获取当前应用的访问虚拟目录
-
String getRealPath(String path) 根据虚拟目录获取应用部署的磁盘绝对路径
-
void setAttribute(String name,Object value) 向应用域对象中存储数据
-
Object getAttribute(String name) 通过名称获取应用域对象中的数据
-
void removeAttribute(String name) 通过名称移除应用域对象中的数据