文章目录
Servlet
获取参数
获取参数并添加到数据库中
AddServlet.java
package com.sentiment.servlets;
import com.sentiment.fruit.dao.impl.FruitDAOImpl;
import com.sentiment.fruit.pojo.Fruit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AddServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer count = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
System.out.println(fname);
System.out.println(price);
System.out.println(count);
System.out.println(remark);
FruitDAOImpl fruitDAO = new FruitDAOImpl();
fruitDAO.addFruit(new Fruit(0,fname,price,count,remark));
System.out.println("添加成功");
}
}
add.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Servlet</title>
</head>
<body>
<form action="add" method="post">
名称:<input type="text" name="fname"><br/>
价格:<input type="text" name="price"><br/>
库存:<input type="text" name="fcount"><br/>
备注:<input type="text" name="remark"><br/>
<input type="submit" value="添加">
</form>
</body>
</html>
web.xml
<servlet>
<servlet-name>AddServlet</servlet-name>
<servlet-class>com.sentiment.servlets.AddServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddServlet</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
单击添加,添加成功
流程
1、点击添加时,action=add
2、找到url-pattren = /add
3、就找到了
<servlet-name>
—>AddServlet4、servlet-mapping中的AddServlet对应了servlet的AddServlet
5、对应上之后找到了com.sentiment.servlets.AddServlet
6、发送post请求,并有AddServlet的doPost方法接收
设置编码
前边添加数据时,其实遇到一些问题,当添加中文名称时会出现乱码的情况,所以需要手动设置一下编码格式
POST
设置成UTF-8即可
req.setCharacterEncoding("UTF-8");
GET
GET方式麻烦一些,由于tomcat默认使用的是ISO-8859-1编码,所以需要先获取此编码的字节,之后再转换成UTF-8
String fname = req.getParameter("fname");
byte[] bytes = fname.getBytes("ISO-8859-1");
fname= new String(bytes,"UTF-8");
继承关系
继承关系
javax.servlet.Servlet 接口
javax.servlet.GenericServlet 抽象类
javax.servlet.http.HttpServlet 抽象子类
相关方法
javax.servlet.Servlet接口:
void init(config) - 初始化方法
void service(request,response) - 服务方法
void destory() - 销毁方法
javax.servlet.GenericServlet抽象类:
public abstract void service(request, response) - 仍然是抽象方法
javax.servlet.http.HttServlet 抽象子类:
void service (request,response) - 不是抽象的
看一下HttpServlet方法
①:获取请求方式 (一共有八种请求方式,这里以GET为例)
②:判断为GET后,执行getLastModified()
方法,而这个方法默认返回值就是-1L
③:经过if判断之后调用了本类中的doGet方法
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_get_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
而本类中的doGet方法,相当于默认返回错误信息,该信息的值封装在http.method_get_not_supported
中,而这些信息都在LocalStrings
的配置文件中
因此为了避免报错,才需要我们在传入对应请求前,重写对应的do方法
生命周期
Servlet的生命周期对应了三个方法:init()、service()、destroy()
当第一次接收请求时,servlet会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service ()),最后当容器关闭时,其中的所有的servlet实例会被销毁,调用销毁方法(destroy()),当初始化过后每一次请求都会调用对应的service()方法
package com.sentiment.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Demo01 extends HttpServlet {
public Demo01() {
System.out.println("正在实例化.....");
}
@Override
public void init() throws ServletException {
System.out.println("正在初始化.....");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("正在启动服务.....");
}
@Override
public void destroy() {
System.out.println("正在销毁.....");
}
}
当服务启动后 第一次发出请求时便会执行对应的构造器、init()、service()方法
而当服务关闭时则会执行destory()
初始化时机
默认情况下,实例化和初始化只会执行一次,这样做可以提高系统的启动速度,但如果我们需要提高响应速度则需设置一个参数
<load-on-startup>
通过它可以设置servlet的启动顺序,数字越小启动越靠前,最小值为0
设置了该参数后,在启动环境时会默认进行实例化和初始化,避免了第一次请求后的实例化和初始化操作
线程安全问题
Servlet的线程安全问题 | Y4tacker’s Blog
为了避免线程安全问题可采取:
①不要去修改成员变量的值
②不要去根据成员变量的值做一些逻辑判断
会话
HTTP无状态
看会话前先了解一下HTTP无状态
HTTP无状态:服务器无法判断这两次请求是同一个客户端发过来的,还是不同的客户端发过来的
会话跟踪技术
HTTP无状态会遇到一个问题︰第一次请求是添加商品到购物车,第二次请求是结账;如果这两次请求服务器无法区分是同一用户请求的
这时就要通过会话跟踪技术也就是seesion来解决
public class Demo02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//服务器获取Session,如果没有则创建一个
HttpSession session = req.getSession();
System.out.println(session.getId());
}
}
常用API
- request.getsession () ->获取当前的会话,没有则创建一个新的会话
- request.getsession (true) ->效果和不带参数相同
- request.getsession (false)->获取当前会话,没有则返回null,不会创建新的
- session.getId () ->获取sessionID
- session.isNew ( ) ->判断当前session是否是新的
- session.getMaxInactiveInterval () -> session的非激活间隔时长,默认1800秒session.setMaxInactiveInterval ()
- session.invalidate () ->强制性让会话立即失效
- getSession().setAttribute() -> 设置session
- getSession().getAttribute() -> 获取seesion值
服务器端转发和客户端重定向
服务器内部转发
一次请求响应的过程,对于有客户端而言,内部经过了多少次转发,客户端是不知道的
地址栏没有变化
req.getRequestDispatcher("test6").forward(req,resp);
客户端重定向
两次请求响应的过程。客户端肯定知道请求URL有变化
地址栏有变化
resp.sendRedirect("test6");
Demo05
public class Demo05 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo05......");
//req.getRequestDispatcher("test6").forward(req,resp);
resp.sendRedirect("test6");
}
}
Demo06
public class Demo06 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo06......");
}
}
当启动服务访问test5后,若使用的是服务端转发,则url不变,但是会跳转到demo06输出demo06......
当使用客户端重定向后,url会随之从test5变为test6并输出demo06.........
Thymeleaf
Thymeleaf视图模板技术
物理视图
在Servlet中,将请求转发到一个HTML页面文件时,使用的完整的转发路径就是物理视图。
/pages/user/login_success.html
如果我们把所有的HTML页面都放在某个统一的目录下,那么转发地址就会呈现出明显的规律:
/pages/user/login.html
/pages/user/login_success.html
/pages/user/regist.html
/pages/user/regist_success.html
……
路径的开头都是:/pages/user/
路径的结尾都是:.html
所以,路径开头的部分我们称之为视图前缀,路径结尾的部分我们称之为视图后缀。
逻辑视图
物理视图=视图前缀+逻辑视图+视图后缀
上面的例子中:
视图前缀 | 逻辑视图 | 视图后缀 | 物理视图 |
---|---|---|---|
/pages/user/ | login | .html | /pages/user/login.html |
/pages/user/ | login_success | .html | /pages/user/login_success.html |
服务端引入Thymeleaf
- 引入jar包
2、新建一个Servlet类ViewBaseServlet
package com.sentiment.myssm.myspringmvc;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
@Override
public void init() throws ServletException {
// 1.获取ServletContext对象
ServletContext servletContext = this.getServletContext();
// 2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext());
// 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
3、添加web.xml配置文件设置物理逻辑视图
<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<context-param>
<param-name>view-prefix</param-name>
<param-value>/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html</param-value>
</context-param>
4、将我们使用的Servlet继承与ViewBaseServlet
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
FruitDao fruitDao = new FruitDaoImpl();
List<Fruit> fruitList = fruitDao.getFruitList();
HttpSession session = req.getSession();
session.setAttribute("fruitList",fruitList);
super.processTemplate("index",req,resp);
}
}
5、super.processTemplate(“index”,req,resp);
此时访问index目录,则会回显index.html的信息
Servlet保存作用域
原始情况下,保存作用域我们可以认为有四个:
- page(页面级别,现在几乎不用)
- request(一次请求响应范围)
- session(一次会话范围有效)
- application(一次应用范围有效)
request
demo01
// 演示request保存作用域(demo01和demo02)
@WebServlet("/demo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、向request保存作用域 保存数据
req.setAttribute("uname","Sentiment");
//2、客户端重定向
//resp.sendRedirect("demo02");
//3、服务端转发
req.getRequestDispatcher("demo02").forward(req,resp);
}
}
demo02
@WebServlet("/demo02")
public class ServletDemo02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object uname = req.getAttribute("uname");
System.out.println(uname);
}
}
由于是request方式,只有在一次响应范围内才能获取到相应的数据,所以当时用重定向时就相当于访问了demo01,之后重定向到了demo02,此时就相当于页面再次请求到了demo02,所以在ServletDemo02输出的uname
值为null
而当使用服务端转发的方式,其实就是通过一次demo01的请求,在内部转发到了demo02,所以一次请求内有效输出Sentiment
session
demo03
// 演示session保存作用域(demo03和demo04)
@WebServlet("/demo03")
public class ServletDemo03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、向request保存作用域 保存数据
req.getSession().setAttribute("uname","Sentiment");
//2、客户端重定向
resp.sendRedirect("demo04");
//3、服务端转发
//req.getRequestDispatcher("demo04").forward(req,resp);
}
}
demo04
@WebServlet("/demo04")
public class ServletDemo04 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object uname = req.getSession().getAttribute("uname");
System.out.println(uname);
}
}
Seesion方式是一次会话内有效,所以不论是客户端重定向还是端口转发都是在一次会话内,所以当访问demo03,便会输出Sentiment
但此时如果换浏览器之后,再去访问demo04,则会返回null,因为不在同一会话内
application
demo05
// 演示application保存作用域(demo05和demo06)
@WebServlet("/demo05")
public class ServletDemo05 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、向application保存作用域 保存数据
//ServletContext:Servlet上下文
ServletContext applicatioin = req.getServletContext();
applicatioin.setAttribute("uname","Sentiemnt");
//2、客户端重定向
resp.sendRedirect("demo06");
//3、服务端转发
//req.getRequestDispatcher("demo06").forward(req,resp);
}
}
demo06
@WebServlet("/demo06")
public class ServletDemo06 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object uname = req.getSession().getServletContext().getAttribute("uname");
System.out.println(uname);
}
}
application一次应用范围有效,所以无论何种方式,只要不重启服务,则都会获取到uname
项目实战
Thymeleaf入门到吃灰 - 鞋破露脚尖儿 - 博客园 (cnblogs.com)
编辑修改仓库信息
将之前的html拿过来,这里想通过点击水果的链接获取fid并跳转到对应的修改页面,有两种链接方式:
<-- 字符串拼接 -->
<td><a th:text="${fruit.fname}" th:href="@{'/edit.do?fid='+${fruit.fid}}">苹果</a></td>
<-- 括号代替问号传参部分 -->
<td><a th:text="${fruit.fname}" th:href="@{/edit.do(fid=${fruit.fid})}">苹果</a></td>
这样当我们点击链接时便会跳转到/edit.do?fid=fruit.fid的页面,所以需要设置一个/edit.do路径
@WebServlet("/edit.do")
public class EditServlet extends ViewBaseServlet {
private FruitDao fruitDao=new FruitDaoImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fidStr = req.getParameter("fid");
if (fidStr!=null && !"".equals(fidStr)){
int fid = Integer.parseInt(fidStr);
Fruit fruit = fruitDao.getFruitByFid(fid);
req.setAttribute("fruit",fruit);
super.processTemplate("edit",req,resp);
}
}
}
访问/edit.do时会获取fid信息,若不为空,则会赋值给fruit,并跳转到edit.html页面,也就是修改页面
所以此时要写一个修改的页面
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="css/test.css">
</head>
<body>
<div id="div">
<div id="div_list">
<table id="tbl_list" th:object="${fruit}">
<p class="p">欢迎来到水果售货系统3!</p>
<tr>
<th>名称:</th>
<!-- <td><input type="text" name="fname" th:value="${fruit.fname}"></td>-->
<td><input type="text" name="fname""></td>
</tr>
<tr>
<th>单价:</th>
<td><input type="text" name="price""></td>
</tr>
<tr>
<th>库存:</th>
<td><input type="text" name="fcount""></td>
</tr>
<tr>
<th>备注:</th>
<td><input type="text" name="remark""></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" value="修改">
</th>
</tr>
</table>
</div>
</div>
</body>
</html>
设置默认值
<td><input type="text" name="fname" th:value="${fruit.fname}"></td>
<td><input type="text" name="price" th:value="${fruit.price}"></td>
......
这种方式前边都有fruit重用写过高,所以可以换成<th:object="${fruit}"> 和*{属性}
的形式来降低重用
此时当点击链接后,则会跳转到对应的页面,并且上边会有默认的值
但此时的修改按钮还没有给任何的值,所以并没有修改功能,所以在table外添加一个表单,当点击提交时,则会通过post的方式将值发送给/update.do
<form th:action="@{/update.do}" method="post" th:object="${fruit}">
这就需要写一个接受/update.do的类
@WebServlet("/update.do")
public class UpdateServlet extends ViewBaseServlet {
private FruitDao fruitDao=new FruitDaoImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码
req.setCharacterEncoding("UTF-8");
//2、获取参数
String fidStr = req.getParameter("fid");
int fid = Integer.parseInt(fidStr);
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
int price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
int fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
//3、执行更新
fruitDao.updateFruit(new Fruit(fid,fname,price,fcount,remark));
//4、资源跳转
//super.processTemplate("index",req,resp);
resp.sendRedirect("index");
}
}
获取各个参数,并执行updateFruit方法,最终跳转到index.html查看修改后信息
添加和删除
删除
现在图片上添加一个delete事件
<td><img src="imgs/1.jpg" class="image" th:onclick="|delFruit(${fruit.fid})|"></td>
编写delFruit事件
function delFruit(fid){
if (confirm("是否确认删除?")){
window.location.href='del.do?fid='+fid
}
}
当点击确认按钮后,会跳转到del.do?fid=fid,所以需要写一个/del.do来接受参数
@WebServlet("/del.do")
public class DelServlet extends ViewBaseServlet {
private FruitDao fruitDao=new FruitDaoImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fidStr = req.getParameter("fid");
if (fidStr!=null && !"".equals(fidStr)){
int fid = Integer.parseInt(fidStr);
fruitDao.delteFruit(fid);
resp.sendRedirect("index");
}
}
}
当删除后重定向到index界面
添加
在index.html写一个添加库存的链接
<div id="add_fruit">
<a href="add.html">添加库存记录</a>
</div>
跳转到add.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="css/test.css">
<script language="JavaScript" src="js/index.js"></script>
</head>
<body>
<div id="div">
<div id="div_list">
<form action="add.do" method="post">
<table id="tbl_list">
<p class="p">添加水果库存!</p>
<tr>
<th>名称:</th>
<!--<td><input type="text" name="fname" th:value="${fruit.fname}"></td>-->
<td><input type="text" name="fname"></td>
</tr>
<tr>
<th>单价:</th>
<td><input type="text" name="price" ></td>
</tr>
<tr>
<th>库存:</th>
<td><input type="text" name="fcount"></td>
</tr>
<tr>
<th>备注:</th>
<td><input type="text" name="remark" ></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" value="添加">
</th>
</tr>
</table>
</form>
</div>
</div>
</body>
</html>
当点击添加时,会将传入的数据传到/add.do,最终实现添加效果
@WebServlet("/add.do")
public class AddServlet extends ViewBaseServlet {
private FruitDao fruitDao=new FruitDaoImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码
req.setCharacterEncoding("UTF-8");
//2、获取参数
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
int price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
int fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
//3、执行更新
fruitDao.insertFruit(new Fruit(0,fname,price,fcount,remark));
//4、资源跳转
//super.processTemplate("index",req,resp);
resp.sendRedirect("index");
}
}
这里是通过index.html直接跳转到了add.html,所以在add.html就无法使用thymeleaf了,因为thymeleaf是在Servlet中渲染的,而通过index.html—> add.html之间的跳转并没有经过Serlvet,所以如果协程
th:action="@{/add.do"
,则不会被解释如果想解决此问题,也可以在index.html中先跳转到add.do此时就经过了thymeleaf的渲染,之后再添加一个doGet方法,因为当访问add.do时,其实就相当于调用了doGet,内容为super.processTemplate(“add”,req,resp);跳转到add.html,此时点击添加之后再跳转到doPost方法就不会再出现任何问题
Filter
其实在Filter内存马时候已经了解过,是一种Servlet的规范,在到达Servlet前进行的一段过滤
Servlet
@WebServlet("/demo01.do")
public class Demo01Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo01 service.....");
req.getRequestDispatcher("success.html").forward(req,resp);
}
}
Filter
@WebFilter("/demo01.do")
public class Demo01Filter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("helloA");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("helloA2");
}
@Override
public void destroy() {
}
}
结果
根据图示在理解一下:
当访问/demo01.do时,首先会调用doFilter方法进行过滤,输出helloA,过滤后到达service()方法,之后通过过滤器放行,输出helloA2,再回显给客户端
filter中也可以使用通配符即:@WebFilter("*.do")
,用这种方式来匹配以do结尾的请求
过滤链
分别定义三个:filter1、filter2、filter3,并在放行前后分别输出A1|A2、B1|B2、C1|C2,看一下调用后的结果:
结果
示意图
可以看到三个过滤器的执行过程,但这里引入了一个新问题:如何知道先执行那个过滤器?
- 如果采取的是注解的方式:过滤器链的拦截顺序是按全类名的先后顺序排序的
- 如果采取的是xml的方式:按照配置的先后顺序进行排序
Lisenter
顾名思义就是监听器,他能够监听一些事件从而来达到一些效果。在请求网站的时候, 程序先执行listener监听器的内容:Listener -> Filter -> Servlet
监听器列表
-
ServletContext,服务器启动和终止时触发
- ServletContextListener:监听ServletContext对象的创建和销毁的过程
- HttpSeesionListener:监听HttpSeesion对象的创建和销毁的过程
- ServletRequestListener:监听ServletRequest对象的创建和销毁的过程
-
Session,有关Session操作时触发
- ServletContextAttributeLisenter:监听ServletContext的保存作用域的改动(add、remove、replace)
- HttpSessionAttributeListener:监听HttpSession的保存作用域的改动(add、remove、replace)
- ServletRequestAttributeListener:监听ServletRequest的保存作用域的改动(add、remove、replace)
-
Request,访问服务时触发
- HttpSessionBindingListener -监听某个对象在session域中的创建与移除
- HttpSessionActivationListener -监听某个对象在session域中的序列化和反序列化
测试
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("listener上下文初始化......");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("listener上下文已销毁.......");
}
}
由于Context是在服务启动和销毁时执行,所以当开启服务和销毁服务时,会分别输出上边两条语句
注:
Listener的注解不需要添加路径,因为是伴随服务启动产生的
既然不需要加路径,所以如果使用web.xml配置的话,也就省去了
<listener-mapping>
后记
感觉除了Serlvet、Filter、Lisenter之外的东西对于安全来说没太有用,并且MVC部分在Spring中能学到,interceptor拦截器Springboot中会有,所以JavaWeb学到这里