jjzjj

JavaWeb三大组件(Servlet、Filter、Listener)

程序猿路野 2023-04-18 原文

前言

JavaWeb三大组件指的是:Servlet 程序、Filter 过滤器、Listener 监听器,它们在JavaWeb开发中分别提供不同的功能,然而很多人有只用过Servlet、Filter,很少接触到Listener,甚至有些人对然而很多人有只用过Servlet都不熟悉,因为在企业开发中,都是使用框架的封装好的,很少接触到原生的JavaWeb组件,充其量就是使用Filter拦截请求,过滤响应,所以很多人上来就直接学框架。

其实这种做法很不可取,虽然随着技术的发展,已经没有人再使用原生JavaWeb开发了,加之前后端分离,像JSP、JDBC等技术都没有了专门学习的必要了。但是JavaWeb的三大组件却是十分重要,框架都是对原生JavaWeb进行封装的结果,像SpringMVC的核心就是Servlet,涉及到Listener的框架就更多了,而Filter不仅在框架使用,日常开发中也经常被用到,所以要深入理解框架,就必须熟练掌握JavaWeb的三大组件。

一、Servlet 程序

Servlet是什么?

Servlet是JavaEE规范(接口)之一;
Servlet是运行在服务器(Web容器Tomcat等)上的一个 java 小程序,它用来接收客户端发送过来的请求进行处理,并响应数据给客户端
Servlet及相对的对象,都由Tomcat创建,我们只是使用。

Servlet需要完成3个任务:

  1. 接收请求:将客户端发送过来的请求封装成ServletRequest对象(包含请求头、参数等各种信息)
  2. 处理请求:在service方法中接收参数,并且进行处理请求。
  3. 数据响应:请求处理完成后,通过转发(forward)或者重定向(redirect)到某个页面。
    转发(forward)或者重定向(redirect)的区别?
    本质:forward是HttpServletRequest的方法,redirect是HttpServletResponse的方法。
    现象及结果:
    1. forward客户端只发了一次请求,在服务端进行转发行为,可以共享数据(request中参数),浏览器URL不改变。
    2. redirect是服务端向客户端完成响应后,客户端再次发起一个请求,不可以共享数据(request中参数),请求了两次,浏览器URL改变。
    

Servlet的生命周期

  1. 执行 Servlet 构造器方法
    第一步,在web.xml中的servlet中配置 load-on-startup 的值 ≥ 0 时,表示应用启动时就创建这个servlet。否则,第一次访问的时候调用。

  2. 执行 init 初始化方法
    第二步,第一次访问的时候调用。

  3. 执行 service 方法
    第三步,每次访问都会调用。

  4. 执行 destroy 销毁方法
    第四步,在 web 工程停止的时候调用。

通过实现 Servlet 接口 实现Servlet程序

  1. 实现Servlet接口,重写service方法,处理请求,并响应数据
  2. 在web.xml中配置servlet程序的访问地址。

web.xml 中的配置:

    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.demo.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

通过继承 HttpServlet 实现Servlet程序(推荐,一般开发中使用这种方式)

  1. 继承 HttpServlet类,按业务需求重写doGet 或 doPost 方法,处理请求
  2. 到 web.xml 中的配置 Servlet 程序的访问地址

代码比实现Servlet接口的方式更加简单,不需要进行请求的类型转换,配置与实现Servlet接口的方式一样,所以这里不做演示

ServletConfig(Servlet程序的配置信息类)

在Servlet 程序创建时,就会创建一个对应的 ServletConfig 对象。

它的三大作用:

  1. 获取web.xml 中 Servlet 程序的别名 servlet-name 的值
  2. 获取web.xml 中 Servlet 程序的获取初始化参数 init-param
  3. 获取 ServletContext 对象

ServletContext (Servlet上下文) 接口

  1. 每个web项目只有一个ServletContext对象,在web工程部署启动的时候创建,在工程停止的时候关闭。
  2. ServletContext 对象是一个域对象(可以像Map一样存储数据的对象。域指的是作用域,这里是整个web工程)。

ServletContext 类的四个作用:

  1. 获取 web.xml 中配置的上下文参数 context-param
  2. getContextPath()获取当前的工程路径,格式: /工程路径
  3. getRealPath()获取工程部署后在服务器硬盘上的绝对路径
  4. 像 Map 一样存取数据

HttpServletRequest 和 HttpServletResponse

HttpServletRequest

HttpServletRequest继承了ServletRequest,每次请求进入tomcat服务器,tomcat容器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中。然后传递到 service 方法(doGet 和 doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的信息

HttpServletResponse

HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。通过 HttpServletResponsee 对象来进行设置返回给客户端的信息

解决请求的中文乱码

  1. Get请求:获取请求参数,先以 iso8859-1 进行编码,再以 utf-8 进行解
  2. Post请求:调用req.setCharacterEncoding("UTF-8"), 设置请求体的字符集为 UTF-8;

解决响应的中文乱码

方案一(推荐):

// 它会同时设置服务器和客户端都使用 UTF-8 字符集,还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8")

方案二(不推荐):

// 设置服务器字符集为 UTF-8
resp.setCharacterEncoding("UTF-8");
// 通过响应头,设置浏览器也使用 UTF-8 字符集
resp.setHeader("Content-Type", "text/html; charset=UTF-8"

Filter

Filter 是JavaEE规范(接口)之一;
Filter 过滤器它的作用是:拦截请求,过滤响应。

常见应用场景:
1、权限检查
2、日记操作
3、事务管理
……等等

Filter 过滤器的使用步骤:

1、实现 Filter 接口,实现过滤方法 doFilter()
2、到 web.xml 中去配置 Filter 的拦截路径

web.xml 中的配置:

<filter>
    <filter-name>AdminFilter</filter-name>
    <filter-class>com.demo.filter.AdminFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>AdminFilter</filter-name>
    <url-pattern>/admin/*</url-pattern>
</filter-mapping>

Filter 的生命周期

  1. 构造器方法
  2. init 初始化方法
    第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)
  3. doFilter 过滤方法
    第 3 步,每次拦截到请求,就会执行
  4. destroy 销毁
    第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)

FilterConfig(Filter过滤器配置类)

Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。

FilterConfig 类的作用是获取 filter 过滤器的配置内容:

  1. 获取 Filter 的名称 filter-name 的内容
  2. 获取在 Filter 中配置的 init-param 初始化参数
  3. 获取 ServletContext 对象

FilterChain 过滤器链

在多个Filter执行的时候,它们执行的优先顺序由它们在web.xml中从上到下配置的filter-mapping顺序决定,与filter的配置顺序无关!!!

过滤器链(多个Filter执行)的特点:

  1. 所有filter和目标资源默认都执行在一个线程中。
  2. 多个filter共同执行的时候,它们使用的是同一个Request对象。

Filter 的3种拦截路径匹配规则:

  • 精确匹配 /target.jsp
  • 目录匹配 /admin/*
  • 后缀名匹配 *.html
    Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在!!!

Listener

用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。本质是观察者模式
Servlet监听器:Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。

监听器分为3类

  • 域对象监听器
  • 域对象的属性域监听器
  • Session域中数据的监听器

八大监听器

  1. ServletContextListener
    监听ServletContext对象的创建与销毁

在SpringMVC中,有个ContextLoaderListener,这个监听器就实现了ServletContextListener接口,表示对ServletContext对象本身的生命周期进行监控
2. HttpSessionListener
监听HttpSession对象的创建与销毁
3. ServletRequestListener
监听ServletRequest对象的创建与销毁
4. ServletContextAttributeListener
监听ServletContext中属性的创建、修改和销毁
5. HttpSessionAttributeListener
监听HttpSession中属性的创建、修改和销毁
6. ServletRequestAttributeListener
监听ServletRequest中属性的创建、修改和销毁
7. HttpSessionBindingListener
监听某个对象在Session域中的创建与移除
8. HttpSessionActivationListener
监听某个对象在Session中的序列化与反序列化。

Listener 监听器的使用步骤:

  1. 实现八大监听器中相应一种,重写相应的方法
  2. 到 web.xml 中去配置 Listener

web.xml 中的配置:

<listener>
    <listener-class>com.demo.listener.HelloListener</listener-class>
</listener>

有关JavaWeb三大组件(Servlet、Filter、Listener)的更多相关文章

  1. ruby-on-rails - before_filter 运行多个方法 - 2

    是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://

  2. ruby-on-rails - Rails 查询 : Filter by properties in another table - 2

    我正在寻找一个清晰的Rails4示例,说明如何根据通过另一个表关联的数据过滤记录。假设我有一个用户模型和一个评论模型。一个用户has_many评论,一个Commentbelongs_to一个用户。评论在其表中也有一个score列。classUserUsers|id|name|email||-----|---------|---------------------||1|"Alice"|"alice@example.com"||2|"Bob"|"bob@example.com"||...|classComment我如何获得所有对内容“k”发表评论且分数>0的用户?请注意,我要返回的是用户

  3. 阿里云,华为云,腾讯云三大公有云厂商,香港地区主机测评 - 2

    三大公有云厂商,香港地区主机测评一、ping时延比对(厦门电信本地测试):Ping时延测试腾讯云阿里云华为云延迟率最低时延44ms,最高72ms,平均46ms47.242段:最低时延59ms,最高204ms,平均107ms最低时延45ms,最高93ms,平均47ms丢包率丢包率小有的ip段丢包率较大每个段都会有概率丢包阿里云:47.242段:最低时延59ms,最高204ms,平均107ms,有的ip段丢包率较大8.210段:最低时延64ms,最高232ms,平均119ms,丢包率较好腾讯云:最低时延44ms,最高72ms,平均46ms,丢包率小华为云:最低时延45ms,最高93ms,平均47m

  4. ruby - 真正的 sinatra(ruby/rack) after_filter 最快的方法是什么? - 2

    好的,这是一个简单的任务。在我向客户端呈现html之后,我想使用请求中的信息执行数据库调用。我正在使用sinatra,因为它是一个轻量级的微框架,但我真的支持ruby​​中的任何东西,如果它更快/更容易(Rack?)。我只想获取url并根据url将客户端重定向到其他地方。那么如何使用rack/sinatra作为一个真正的after_filter。after_filter我的意思是在响应发送到客户端之后。还是没有线程就无法实现?我fork了sinatra并在过滤器之后添加,但是没有办法刷新响应,即使是假设流式传输文件(显然是二进制文件)的send_data也在等待after_filter

  5. Android Studio开发之使用内容组件Content获取通讯信息讲解及实战(附源码 包括添加手机联系人和发短信) - 2

    运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid

  6. ruby - 在没有 rails 的 ruby​​ 中实现一个 rails before_filter - 2

    我在所有类(class)中都使用galogger。我希望每个消息都以类名和方法名开头,如下所示:Class_name::Method_name这就是我现在正在做的:classFOOdefinitializeenddefbarmsg_prefix="#{self.class}::#{__method__}"...somecode...@logeer="#{msg_prefix}msg..."enddefbar2msg_prefix="#{self.class}::#{__method__}"...somecode2...@logeer="#{msg_prefix}msg2..."ende

  7. ruby-on-rails - 如何在 Rails3 应用程序中的所有其他 Controller before_filters 之后在 gem 中附加 before_filter? - 2

    有一个gem,它附加一个before_filter到Rails应用:classRailtie这是应用程序中的一些Controller:classDesktopsController现在的问题是,来自gem的before_filter被放入来自DesktopsController的before_filter之前的过滤器链中:DesktopsController._process_action_callbacks.select{|c|c.kind==:before}.collect{|filter|filter.filter}=>[[0]:set_locale,[1]:set_langua

  8. ruby - 模块化、基于组件的 Sinatra 应用程序的架构 - 2

    我正在开发一个包含大约10个不同功能组件的Sinatra应用程序。我们希望能够将这些组件混合并匹配到应用程序的单独实例中,完全从config.yaml文件配置,如下所示:components:-route:'/chunky'component_type:FoodListercomponent_settings:food_type:baconmax_items:400-route:'places/paris'component_type:Mappercomponent_settings:latitude:48.85387273165654longitude:2.340087890625-

  9. ruby-on-rails - Rails 3 做 skip_before_filter 的方法,:only - 2

    在rails2.8中我们可以这样写skip_before_filterskip_before_filter:require_login,:only=>[:create,:new,:accept]这意味着,我只想将过滤器require_login应用于这些操作[:create,:new,:accept],并跳过其他操作的过滤器。不过好像,这条路是deprecated在rails3中。和新的skip_filter被添加。我试过了skip_filter:require_login,:only=>[:create,:new,:accept]但它不起作用,所以我如何在Rails3中执行此操作。

  10. ruby - 如何使用( ruby ) Rack 中间件组件设置 cookie? - 2

    我正在为需要有条件地设置cookie的Rails应用编写Rack中间件组件。我目前正在尝试设置cookie。通过谷歌搜索,这似乎应该可行:classRackAppdefinitialize(app)@app=appenddefcall(env)@status,@headers,@response=@app.call(env)@response.set_cookie("foo",{:value=>"bar",:path=>"/",:expires=>Time.now+24*60*60})[@status,@headers,@response]endend它不会给出错误,但也不会设置coo

随机推荐