[JavaWeb]——三大组件

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>—>AddServlet

4、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

  1. 引入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学到这里

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值