🧑🎓 个人主页:花棉袄
📖 本章内容:【Tomcat】
📢 版权: 本文由【花棉袄】原创 💝在 CSDN 首发 💝 需要转载请联系博主
📢💨如果文章对你有帮助【关注👍点赞❤️收藏⭐】
🍖WEB概念
1️⃣软件架构
- C/S: 客户端/服务器端 ‐‐‐‐‐‐‐‐‐‐‐‐> QQ 、360 …
- B/S: 浏览器/服务器端 ‐‐‐‐‐‐‐‐‐‐‐‐> 京东、 网易 …
2️⃣资源分类
🌳 静态资源
- 静态资源:所有用户访问后,得到的结果都是一样的
- 静态资源可以直接被浏览器解析
- 如:
html
css
JavaScript
jpg
…
🌳 动态资源
- 动态资源:每个用户访问相同资源后,得到的结果可能不一样
- 动态资源被访问后,需要先转换为静态资源,再返回给浏览器,通过浏览器进行解析
- 如:
servlet/jsp
php
asp
…
3️⃣网络通信三要素
🌳 IP:电子设备(计算机)在网络中的唯一标识
🌳 端口:应用程序在计算机中的唯一标识 – 0~65536
🌳 传输协议:规定了数据传输的规则
- tcp : 安全协议,三次握手 – 速度稍慢
- udp:不安全协议 – 速度快
🥙WEB服务器
1️⃣WEB服务器概念
- 服务器:安装了服务器软件的计算机
- 服务器软件:接收用户的请求,处理请求,做出响应
- web服务器软件:接收用户的请求,处理请求,做出响应
在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目
2️⃣WEB服务器软件
- webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范 – 收费的
- webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范 – 收费的
- JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范 – 收费的
- Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范 – 免费的
🍵Tomcat 安装
- 📢💨TOMCAT下载
1️⃣Tomcat 目录结构
2️⃣Tomcat 启动停止
- 启动:双击 bin/startup.bat 文件
- 停止:双击 bin/shutdown.bat 文件
- 访问:http://localhost:8080
3️⃣Tomcat 源码
- 📢💨TOMCAT下载
- 1) 解压zip压缩包
- 2) 进入解压目录,并创建一个目录,命名为home , 并将conf、webapps目录移入home 目录中
- 3) 在当前目录下创建一个 pom.xml 文件,引入tomcat的依赖包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.tomcat</groupId>
<artifactId>Tomcat8.5</artifactId>
<name>Tomcat8.5</name>
<version>8.5</version>
<build>
<finalName>Tomcat8.5</finalName>
<sourceDirectory>java</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<resources>
<resource>
<directory>java</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>test</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxrpc</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.5.1</version>
</dependency>
</dependencies>
</project>
- 4) 在idea中, 导入该工程
- 没有maven:右键添加maven
- 5) 配置idea的启动类, 配置 MainClass , 并配置 VM 参数
- 修改自己的项目路径
‐Dcatalina.home=E:/JAVA\tomcat/apache-tomcat-8.5.42-src/home
‐Dcatalina.base=E:/JAVA\tomcat/apache-tomcat-8.5.42-src/home
‐Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
‐Djava.util.logging.config.file=E:/JAVA/tomcat/apache-tomcat-8.5.42-src/home/conf/logging.properties
- 6)启动主方法, 运行Tomcat , 访问Tomcat
出现上述异常的原因,是我们直接启动org.apache.catalina.startup.Bootstrap的时候没有加载JasperInitializer,从而无法编译JSP
解决办法是在tomcat的源码ContextConfig中的configureStart函数中手动将JSP解析器初始化:
在ContextConfig类中添加:context.addServletContainerInitializer(new JasperInitializer(), null);
🏵️JavaWeb项目
- WEB工程目录
1️⃣项目创建
- 创建项目(新建一个空项目,然后再新建一个web模块)
- src:存放源代码的
- web:存放项目相关资源的(html、css、js、jsp、图片等)
- WEB-INF:存放相关配置的(web.xml等)
2️⃣应用部署
🌳 点击 Tomcat Server -> Deployment
- After launch:启动tomcat自动以谷歌浏览器打开首页http://localhost:8080/
- update resources , 是tomcat启动之后,我们还可能会修改项目,那这时候不用重新启动tomcat,只需要刷新浏览器,就可以看到修改后的内容
🌳 设置项目路径
🌳 启动项目
- 访问:http://localhost:8080/web/
3️⃣应用发布
🌳在项目的 web 路径下打 war 包:jar -cvf 文件名.war .
jar -cvf war包名称 空格 .
,最后的一个点代表当前路径
- 将打好的 war 包剪切到 tomcat 的 webapps 路径下
- 启动 tomcat 服务,自动解压 war 包
4️⃣配置虚拟目录
🌳虚拟目录的作用:可以发布任意目录下的项目
- 编辑 server.xml 配置文件,找到
<Host>
标签
- path 属性:访问资源的虚拟目录名称
- docBase属性:项目真实存在的路径
- 将之前发布的myweb,copy到E盘下tomcat文件夹下,改名字为tomcat
- 重启tomcat,访问:http://localhost:8080/tomcat
🍏Tomcat 架构
1️⃣HTTP工作原理
- HTTP协议是浏览器与服务器之间的数据传送协议
- 作为应用层协议,HTTP是基于TCP/IP
- 协议来传递数据的(HTML文件、图片、查询结果等)
- TTP协议不涉及数据包(Packet)传输
- 主要规定了客户端和服务器之间的通信格式
2️⃣Tomcat整体架构
- 浏览器发给服务端的是一个HTTP格式的请求,HTTP服务器收到这个请求后
- 需要调用服务端程序来处理,所谓的服务端程序就是你写的Java类
- 一般来说不同的请求需要由不同的Java类来处理
- 1) 图1:表示HTTP服务器直接调用具体业务类,它们是紧耦合的。
- 2) 图2:HTTP服务器不直接调用业务类,而是把请求交给容器来处理容器通过Servlet接口调用业务类
- 因此Servlet接口和Servlet容器的出现,达到了HTTP服务器与业务类解耦的目的
- 而Servlet接口和Servlet容器这一整套规范叫作Servlet规范
- Tomcat按照Servlet规范的要求实现了Servlet容器,同时它们也具有HTTP服务器的功能
- 作为Java程序员,如果我们要实现新的业务功能,只需要实现一个Servlet
- 并把它注册到Tomcat(Servlet容器)中,剩下的事情就由Tomcat帮我们处理了
3️⃣Servlet容器工作流程
- 为了解耦,HTTP服务器不直接调用Servlet,而是把请求交给Servlet容器来处理
🌳 Servlet容器工作流程
- 当客户请求某个资源时,HTTP服务器会用一个
ServletRequest对象把客户的请求信息封装起来
- Servlet容器拿到请求后,
根据请求的URL和Servlet的映射关系
找到相应的Servlet - 如果Servlet还没有被加载,就用
反射机制创建这个Servlet
- 并调用Servlet的init方法来完成初始化,接着调用
Servlet的service方法来处理请求
- 把ServletResponse对象返回给HTTP服务器,
HTTP服务器会把响应发送给客户端
🌳 Tomcat要实现两个核心功能
- 处理Socket连接,负责网络字节流与Request和Response对象的转化
- 加载和管理Servlet,以及具体处理Request请求
🌳 Tomcat设计了两个核心组件
- 连接器:(Connector)
- 容器:(Container)
🥐Servlet开发
1️⃣Servlet介绍
Servlet 是运行在 Java 服务器端的程序,用于接收和响应来自客户端基于 HTTP 协议的请求
如果想实现 Servlet 的功能,可以通过实现 javax.servlet.Servlet 接口或者继承它的实现类
核心方法:service(),任何客户端的请求都会经过该方法
2️⃣Servlet实现方式
- 第一种:实现 Servlet 接口,实现所有的抽象方法。该方式支持最大程度的自定义
- 第二种:继承 GenericServlet 抽象类,必须重写 service 方法,其他方法可选择重写
- 第三种:继承 HttpServlet 抽象类,需要重写 doGet 和 doPost 方法
🌳 创建一个类继承 GenericServlet,重写 service 方法
public class HelloServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("方法执行了");
}
}
- 在 web.xml 中配置 Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>com.michale.javaweb.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
</web-app>
- Servlet执行过程分析
3️⃣Servlet关系视图
4️⃣Servlet的生命周期
- 出生:请求第一次到达 Servlet 时,对象就创建出来,并且初始化成功。只出生(创建)一次,将对象放到内存中
- 活着:服务器提供服务的整个过程中,该对象一直存在,每次都是执行 service 方法
- 死亡:当服务停止时,或者服务器宕机时,对象死亡
🌳Servlet的生命周期结论
- 结论:Servlet 对象只会创建一次,销毁一次
- 所以 Servlet 对象只有一个实例
- 如果一个对象实例在应用中是唯一的存在,那么我们就称它为单例模式
public class HelloServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("对象创建并初始化了...");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("接收到了客户端的请求...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
public void destroy() {
System.out.println("对象销毁了...");
}
}
5️⃣不同映射方式
- 第一种:
具体名称的方式
- 第二种:
/ 开头 + 通配符的方式
- 第三种:
通配符 + 固定格式结尾的方式
6️⃣Servlet创建时机
第一次访问时创建:
<load-on-startup>1</load-on-startup>
服务器加载时创建:
<load-on-startup>0</load-on-startup>
正整数代表服务器加载时创建,值越小、优先级越高
🥞ServletConfig
1️⃣配置方式
- 在
<servlet>
标签中,通过<init-param>
标签来配置。有两个子标签 <param-name>
:代表初始化参数的 key<param-value>
:代表初始化参数的 value
2️⃣常用方法
3️⃣使用步骤
- web.xml配置
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.demo01.HelloServlet</servlet-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>name</param-name>
<param-value>michale</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello-servlet</url-pattern>
</servlet-mapping>
- 创建TestServletConfig类继承HttpServlet
public class TestServletConfig extends HttpServlet {
//声明ServletConfig配置对象
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 {
//获取key值
String name = config.getInitParameter("name");
System.out.println("name:"+name);
//获取所有的key
Enumeration<String> names = config.getInitParameterNames();
//遍历得到的key
while(names.hasMoreElements()) {
//获取每一个key
String key = names.nextElement();
//通过key获取value
String value = config.getInitParameter(key);
System.out.println("name:" + key + ",value:" + value);
}
//获取ServletContext对象
ServletContext context = config.getServletContext();
System.out.println(context);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
🥪ServletContext
- ServletContext 是应用上下文对象
- 每一个应用中只有一个 ServletContext 对象
- 作用:可以获得应用的全局初始化参数和达到 Servlet 之间的数据共享
1️⃣配置方式
ServletContext 并不属于某个 Servlet 的配置,而是针对于整个应用的配置,也叫全局的初始化参数
在
<web-app>
标签中,通过<context-param>
标签来配置。有两个子标签<param-name>
:代表全局初始化参数的 key<param-value>
:代表全局初始化参数的 value
2️⃣常用方法
3️⃣使用步骤
- 准备工作:新建三个空的txt文件,如下
- 配置Servlet,并且配置ServletContext
<web-app>
....
<!--配置Servlet-->
<servlet>
<servlet-name>servletContextDemo</servlet-name>
<servlet-class>com.example.demo01.ServletContextDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletContextDemo</servlet-name>
<url-pattern>/servletContextDemo</url-pattern>
</servlet-mapping>
<!--配置ServletContext-->
<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>
- 继续在ServletContextDemo中写
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext对象
ServletContext context = getServletContext();
//获取全局配置的globalEncoding
String value = context.getInitParameter("globalDesc");
System.out.println(value);
//获取应用的访问虚拟目录
String contextPath = context.getContextPath();
System.out.println(contextPath);
//根据虚拟目录获取应用部署的磁盘绝对路径
String realPath = context.getRealPath("/");
System.out.println(realPath);
//获取b.txt文件的绝对路径
String b = context.getRealPath("/b.txt");
System.out.println(b);
//获取c.txt文件的绝对路径
String c = context.getRealPath("/WEB-INF/c.txt");
System.out.println(c);
//获取a.txt文件的绝对路径
String a = context.getRealPath("/WEB-INF/classes/a.txt");
System.out.println(a);
}
🌳 共享数据
//修改ServletContextDemo:存储数据
//向域对象中存储数据
context.setAttribute("username","zhangsan");
//修改ServletConfigDemo:获取数据
//获取ServletContextDemo设置共享的数据
Object username = context.getAttribute("username");
System.out.println(username);
🍜Request
- 协议无关的对象标准是:ServletRequest
- 协议相关的对象标准是:HttpServletRequest
1️⃣获取各种路径
2️⃣获取请求头信息
3️⃣获取请求参数
4️⃣解决乱码
//设置编码格式
req.setCharacterEncoding("UTF-8");
5️⃣请求转发
🍞Response
协议无关的对象标准是:ServletResponse接口
协议相关的对象标准是:HttpServletResponse接口
1️⃣状态码首位含义
状态码 | 说明 |
---|---|
1xx | 消息 |
2xx | 成功 |
3xx | 重定向 |
4xx | 客户端错误 |
5xx | 服务器错误 |
2️⃣常用方法介绍
3️⃣解决乱码
🌳项目中常用的编码格式是u8,而浏览器默认使用的编码是gbk–导致乱码!
- 解决方式一:修改浏览器的编码格式(不推荐,不能让用户做修改的动作)
- 解决方式二:通过输出流写出一个标签:
<meta http-equiv='content-type' content='text/html;charset=UTF-8'>
- 解决方式三:
response.setHeader("Content-Type","text/html;charset=UTF-8");
- 解决方式四:
resp.setContentType("text/html;charset=UTF-8");
4️⃣设置缓存时间
- 缓存:对于不经常变化的数据,我们可以设置合理缓存时间,以避免浏览器频繁请求服务器
返回值 | 方法名 | 说明 |
---|---|---|
void | setDateHeader(String name,long time) | 设置消息头添加缓存 |
resp.setDateHeader("Expires",(System.currentTimeMillis()+1*60*60*1000L));
5️⃣设置定时刷新
- 定时刷新:过了指定时间后,页面自动进行跳转
返回值 | 方法名 | 说明 |
---|---|---|
void | setHeader(String name,String value) | 设置消息头定时刷新 |
resp.setHeader("Refresh","3;URL="+req.getContextPath()+"/login.html");
6️⃣请求重定向
🍑@WebServlet
配置方式
@WebServlet注解配置
@WebServlet("/servletDemo1")
public class ServletDemo1 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servlet执行了...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
🤝🏽会话技术
1️⃣会话技术介绍
🌳 会话:浏览器和服务器之间的多次请求和响应 (一次对话)
为了实现一些功能,浏览器和服务器之间可能会产生多次的请求和响应
从浏览器访问服务器开始,到访问服务器结束(关闭浏览器、到了过期时间)
这期间产生的多次请求和响应加在一起就称之为浏览器和服务器之间的一次会话
会话过程中所产生的一些数据,可以通过会话技术( Cookie 和 Session )保存
🌳 cookie&session到底是干嘛用的呢?
- 存储数据,用户登录状态
2️⃣会话管理分类
🌳Cookie:客户端会话管理技术
- 把要共享的数据保存到客户端
- 每次请求时,把会话信息带到服务器端,从而实现多次请求的数据共享
🌳 Session:服务器端会话管理技术
- 本质也是采用客户端会话管理技术
- 只不过在客户端保存的是一个特殊标识,而共享的数据保存到了服务器端的内存对象中
- 每次请求时,会将特殊标识带到服务器端,根据这个标识来找到对应的内存空间,从而实现数据共享
3️⃣客户端会话管理技术
🌳 Cookie:客户端会话管理技术
- 把要共享的数据保存到客户端(浏览器)
- 每次请求时,浏览器会把会话信息带到服务器端,从而实现多次请求的数据共享
- 作用:可以保存客户端访问网站的相关内容,从而保证每次访问时先从本地缓存中获取,以此提高效率!
🌳 Cookie的常见属性
属性名称 | 属性作用 | 是否重要 |
---|---|---|
name | cookie的名称 | 必要属性 |
value | cookie的值(不能是中文) | 必要属性 |
path | cookie的路径 | 重要 |
domain | cookie的域名 | 重要 |
maxAge | cookie的生存时间 | 重要 |
version | cookie的版本号 | 不重要 |
comment | cookie的说明 | 不重要 |
🌳 Cookie有
大小,个数
的限制:每个网站最多只能存20个cookie,且大小不能超过4kb
- 当删除Cookie时,设置maxAge值为0
- 当不设置maxAge时,使用的是浏览器的内存,当关闭浏览器之后,cookie将丢失
- 设置了此值,就会保存成缓存文件(值必须是大于0的,以秒为单位)
🌳 Cookie的方法和添加获取
添加:HttpServletResponse响应对象中提供了addCookie()方法
获取:
HttpServletRequest请求对象
中提供了getCookies()方法
补充:为啥是响应对象添加cookie,而获取对象是请求对象?
- 因为:cookie是通过服务器端代码将数据保存在浏览器,所以服务器让浏览器做一件事情,肯定是通过响应
- 而在浏览器存储的数据,要想告诉服务器都有什么,那肯定是通过请求
🌳 基于响应头set-cookie和请求头cookie实现
🌳Cookie的使用
1.创建Cookie对象,绑定数据
new Cookie(String name, String value)
2.发送Cookie对象
response.addCookie(Cookie cookie)
3.获取Cookie,拿到数据
request.getCookies()
🌳Cookie的使用细节
- 一次可不可以发送多个cookie?
- 可以
- 创建多个Cookie对象,使用response调用多次addCookie方法--发送cookie即可
- cookie能不能存中文?
- 在tomcat 8 之前 cookie中不能直接存储中文数据
需要将中文数据转码 一般采用URL编码(%E3)
- 在tomcat 8 之后,cookie支持中文数据
特殊字符还是不支持,建议使用URL编码存储,URL解码解析
- 数量限制
- 每个网站最多只能有 20 个 Cookie,且大小不能超过 4KB
- 所有网站的 Cookie 总数不能超过 300 个
- 名称限制
- Cookie 的名称只能包含 ASCCI 码表中的字母、数字字符
- 不能包含逗号、分号、空格,不能以 $ 开头
- Cookie 的值不支持中文
- 存活时间限制 setMaxAge() 方法接收数字
- 负整数:当前会话有效,浏览器关闭则清除
- 0:立即清除
- 正整数:以秒为单位设置存活时间
- cookie共享问题?
- 在一个tomcat服务器中,部署了多个web项目,这些web项目中cookie在默认情况下cookie不能共享
- setPath(String path):设置cookie的获取范围,默认情况下设置当前的虚拟目录。如果要共享,则可以将path设置为"/"
- 不同的tomcat服务器间cookie共享问题?
- setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享。
- setDomain(".baidu.com")
- 那么 tieba.baidu.com 和 news.baidu.com中cookie可以共享
- 访问路径限制
- 默认路径:取自第一次访问的资源路径前缀。只要以这个路径开头就能访问到
- 设置路径:setPath() 方法设置指定路径
- Cookie的特点
- cookie存储数据在客户端浏览器
- cookie一般用于存出少量的不太敏感的数据
- 在不登录的情况下,完成服务器对客户端的身份识别
4️⃣服务端会话管理技术
🌳 HttpSession:服务器端会话管理技术
- 本质也是采用客户端会话管理技术
- 只不过在客户端保存的是一个特殊标识,而共享的数据保存到了服务器端的内存对象中
- 每次请求时,会将特殊标识带到服务器端,根据这个标识来找到对应的内存空间,从而实现数据共享
- 是 Servlet 规范中四大域对象之一的会话域对象
🌳HttpSession作用
- 可以实现数据共享
- 为了防止在 一次会话中,让用户多次登录(用户登录状态)
🌳 域对象API
域对象 | 功能 | 作用 |
---|---|---|
ServletContext | 应用域 | 在整个应用域之间实现数据共享 |
ServletRequest | 请求域 | 在当前的请求或转发之间实现数据共享 |
HttpSession | 会话域 | 在当前会话范围之间实现数据共享 |
🌳 HttpSession的常用方法
返回值 | 方法名 | 说明 |
---|---|---|
void | setAttribute(String name,Object value) | 设置共享数据 |
Object | getAttribute(String name) | 获取共享数据 |
void | removeAttribute(String name) | 移除共享数据 |
String | getId() | 获取唯一标识 |
void | Invalidate() | 让session立即失效 |
🌳 HttpSession的获取
- 获取HttpSession是通过
HttpServletRequest
接口中的两个方法获取的
返回值 | 方法名 | 说明 |
---|---|---|
HttpSession | getSession() | 获取HttpSession对象 |
HttpSession | getSession(boolean create) | 获取HttpSession对象,未获取到是否自动创建 |
🌳 Session原理
- Session的实现是依赖于Cookie的
🌳 Session的使用细节
- 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
- 默认情况下:不是
- 设置最大存活时间,让cookie持久化保存
//1.获取session
HttpSession session = request.getSession();
//2.期望客户端关闭后,session也能相同
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);
- 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
- 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
- session的钝化:在服务器正常关闭之前,将session对象系列化到硬盘上
- session的活化:在服务器启动后,将session文件转化为内存中的session对象即可
🌳 HttpSession的钝化和活化
- 什么是钝化和活化
- 钝化:序列化。把长时间不用,但还不到过期时间的 HttpSession 进行序列化,写到磁盘上
- 活化:相反的状态
- 何时钝化
- 第一种情况:当访问量很大时,服务器会根据 getLastAccessTime 来进行排序,对长时间不用,但是还没到过期时间的 HttpSession 进行序列化。
- 第二种情况:当服务器进行重启的时候,为了保持客户 HttpSession 中的数据,也要对其进行序列化
- 注意:HttpSession 的序列化由服务器自动完成,我们无需关心
🍭过滤器-Filter
过滤器——Filter,它是JavaWeb三大组件之一。另外两个是Servlet和Listener
过滤器一般用于完成通用的操作,例如:登录验证、统一编码处理、敏感字符过滤 ~~~
- 处理**通用**操作: 统一编码处理
- 处理**拦截**操作:权限校验,如果有权限那就放行,如果没有就拦截
- 过滤器会做两件事情:拦截,筛选/过滤
1️⃣核心方法
2️⃣配置方式
🌳 注解方式
- 注解方式
@WebFilter(拦截路径)
🌳 配置文件方式
- 多个过滤器使用顺序
- 如果有多个过滤器,取决于过滤器映射的顺序
- 也就是filter-mapping配置的先后顺序
3️⃣FilterChain
- FilterChain 是一个接口,代表过滤器链对象
- 由 Servlet 容器提供实现类对象,直接使用即可
4️⃣过滤器的使用
- 新建ServletDemo01
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servletDemo01执行了...");
//resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("servletDemo01执行了...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
- 新建ServletDemo02
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servletDemo02执行了...");
//resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("servletDemo02执行了...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
- 发现demo1和demo2都是乱码
/*
过滤器基本使用
/*:表明访问当前应用下任何资源,此过滤器都会起作用
*/
@WebFilter("/*")
public class FilterDemo01 implements Filter{
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filterDemo01执行了...");
//处理乱码
servletResponse.setContentType("text/html;charset=UTF-8");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
}
5️⃣ 生命周期
- 创建(出生)
- 当应用加载时实例化对象并执行 init 初始化方法
- 服务(活着)
- 对象提供服务的过程,执行 doFilter 方法
- 只要应用一直提供服务,对象就一直存在
- 销毁(死亡)
- 当应用卸载时或服务器停止时对象销毁。执行 destroy 方法
@WebFilter("/*")
public class FilterDemo03 implements Filter{
/*
初始化方法
*/
@Override
public void init(FilterConfig filterConfig) {
System.out.println("对象初始化成功了...");
}
/*
提供服务方法
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filterDemo03执行了...");
//处理乱码
servletResponse.setContentType("text/html;charset=UTF-8");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
/*
对象销毁
*/
@Override
public void destroy() {
System.out.println("对象销毁了...");
}
}
6️⃣过滤器配置对象
- FilterConfig 是一个接口。代表过滤器的配置对象,可以加载一些初始化参数
@WebFilter("/*")
public class FilterDemo04 implements Filter{
/*
初始化方法
*/
@Override
public void init(FilterConfig filterConfig) {
System.out.println("对象初始化成功了...");
//获取过滤器名称
String filterName = filterConfig.getFilterName();
System.out.println(filterName);
//根据name获取value
String username = filterConfig.getInitParameter("username");
System.out.println(username);
}
/*
提供服务方法
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filterDemo04执行了...");
//处理乱码
servletResponse.setContentType("text/html;charset=UTF-8");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
/*
对象销毁
*/
@Override
public void destroy() {
System.out.println("对象销毁了...");
}
}
🦪监听器-Listener
- 事件源:触发事件的对象
- 事件:触发的动作,里面封装了事件源
- 监听器:当事件源触发事件时,要做的事情。一般是一个接口,由使用者来实现
🌳 注解方式
- 注解方式 @WebListener
🌳 配置文件方式
<!--配置监听器-->
<listener>
<listener-class>com.itheima.listener.ServletContextListenerDemo</listener-class>
</listener>
1️⃣监听对象的监听器
ServletContextListener:用于监听
ServletContext
对象的创建和销毁HttpSessionListener:用于监听
HttpSession
对象的创建和销毁ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁
2️⃣监听域对象属性变化的监听器
ServletContextAttributeListener:用于监听
ServletContext
应用域中属性的变化HttpSessionAttributeListener:用于监听
HttpSession
会话域中属性的变化ServletRequestAttributeListener:用于监听
ServletRequest
请求域中属性的变化
3️⃣监听会话相关的感知性监听器
HttpSessionBindingListener:用于感知对象和会话域绑定的监听器
HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器
4️⃣监听器的使用
- ServletContextAttributeListener的使用
/*
应用域对象中的属性变化的监听器
*/
@WebListener
public class ServletContextAttributeListenerDemo implements ServletContextAttributeListener{
/*
向应用域对象中添加属性时执行此方法
*/
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("监听到了属性的添加...");
//获取应用域对象
ServletContext servletContext = scae.getServletContext();
//获取属性
Object value = servletContext.getAttribute("username");
System.out.println(value);
}
/*
向应用域对象中替换属性时执行此方法
*/
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("监听到了属性的替换...");
//获取应用域对象
ServletContext servletContext = scae.getServletContext();
//获取属性
Object value = servletContext.getAttribute("username");
System.out.println(value);
}
/*
向应用域对象中移除属性时执行此方法
*/
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("监听到了属性的移除...");
//获取应用域对象
ServletContext servletContext = scae.getServletContext();
//获取属性
Object value = servletContext.getAttribute("username");
System.out.println(value);
}
}
- 修改ServletContextListenerDemo:在contextInitialized中增加如下代码:
//添加属性
servletContext.setAttribute("username","zhangsan");
//替换属性
servletContext.setAttribute("username","lisi");
//移除属性
servletContext.removeAttribute("username");
📢💨如果文章对你有帮助【关注👍点赞❤️收藏⭐】
🏅 JAVA入门到飞起:《基础阶段》
🏅 第一阶段:📢💨 JAVA基础
🏅 第二阶段:📢💨 JAVA进阶
🏅 第三阶段:📢💨 Tomcat
🏅 第四阶段:📢💨 Nginx