Web Components

Web Components

EE规范其实对于Web组件一共定义了三个标准,其中之一就是我们经常使用的Servlet,除此之外还有另外两个组件

  • Listener:监听器。监听某一个对象的创建、销毁、属性的变更等。可以把之前写在某个servlet的init方法里面的代码写在listener里面。
  • Filter:过滤器。拦截、过滤。黑名单。订单、个人主页

Listener

简单介绍一下。使用场景并不是特别的多,只有一个ServletContextListener需要记住。
监听器。类比一下现实生活中的监听器

  • 被监听对象:明星艺人
  • 被监听事件:行为
  • 监听者:朝阳人民群众
  • 触发事件:报警

web中的监听器

  • 被监听对象:ServletContext
  • 被监听事件:该对象的创建、销毁
  • 监听者:自己编写一个监听器
  • 触发事件:调用监听器里面的对应代码

web中的监听器一共可以分为三大类8种
1.三个域对象创建、销毁的监听器 ServletContextListener
2.三个域对象属性变更的监听器
3.session数据钝化、活化的监听器

其中ServletContextListener监听器,大家需要有一个印象,后面学习Spring框架,它会在该监听器里面进行实例化。

ServletContextListener使用(掌握)

1.编写一个类实现ServletContextListener接口

2.声明该Listener

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("context init");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("context destroy");
    }
}

怎么实现的呢?

tomcat的代码是很多年以前已经写好的,它是如何调用后面你写得代码呢?

原理(不做统一要求)

宝宝哭---------爸爸妈妈做出反应
Web Components_第1张图片

Web Components_第2张图片

package test.update;

public class BabyTest {

    public static void main(String[] args) {
        Baby baby = new Baby();
//        baby.addRelationShip(new Dad());
//        baby.addRelationShip(new Mom());
        baby.addRelationShip(new GrandPa());
        baby.addRelationShip(new GrandMa());
        baby.cry();
    }
}
package test.update;

import java.util.ArrayList;
import java.util.List;

public class Baby {

    private List<RelationShip> relations = new ArrayList<>();

    public void addRelationShip(RelationShip relationShip){
        this.relations.add(relationShip);
    }

    public void cry(){
        for (RelationShip relation : relations) {
            relation.action();
        }
    }
}
ServletContext {
​	List <ServletContextListener> listeners
    add(){
}

init方法会在servletContext被创建之后调用

init(){
 listeners.for-------> listener.contextInitialized();
}

destroy(){
​	listeners.for----->listener.contextDestroyed();
}
}

观察者设计模式。监听器设计模式

Filter

其实和Servlet大多数情况下是一致的,所以套着Servlet来就可以了。

使用及生命周期

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/filter1")
public class FirstFilter implements Filter {

    //会在应用启动的时候直接实例化一个对象出来,然后执行init方法
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter doFilter");
    }

    //应用被卸载、服务器关闭
    @Override
    public void destroy() {
        System.out.println("filter destroy");
    }
}

filter和servlet关联

通过url-pattern产生关联。

注意:filter和servlet设置相同的url-pattern并不会导致出错。从功能的角度去理解。EE规范就是这么定义的
功能上去理解:
servlet:开发动态web资源的组件。一个请求只有一个组件来响应
filter:拦截器、过滤器。它不是主要去做出响应的组件,所以设置它可以和servlet的url-pattern。

注意:filter默认情况下执行的是拦截操作,如果希望filter能够将请求进行进一步下发给后面的组件,那么需要设置一个方法,该方法对于程序的放行至关重要。如果没有这行代码,那么就执行的是拦截操作,加上下面这行代码,那么执行的就是放行操作。

chain.doFilter(request,response)

*filter可不可以设置/呢?

可以的。

filter和filter之间可不可以设置相同的url-pattern呢?

可以的。

如果有多个filter,那么filter的执行先后顺序按照什么来呢?

如果是注解的话,那么按照类名首字母的ASCII先后顺序

如果是web.xml的话,那么按照filter-mapping声明的先后顺序来

请求的完整执行流程

以访问http://localhost/application/servlet1为例,简述整个请求的访问过程

1.浏览器帮助生成一个HTTP请求报文,传输到服务器

2.被监听着80端口号的Connector接收到,将请求报文解析成为request对象,同时生成一个response对象

3.将这两个对象传给engine,engine进一步挑选合适的host,将对象进行进一步下发

4.host的职责就是来挑选一个合适的Context,将这两个对象进行进一步下发

5.Context里面首先根据请求的资源路径/servlet1,先看有没有对应的filter可以处理该请求,就会把满足条件的filter加入到备选中,按照他们的先后顺序(注解 ASCII、web.xml mapping)形成一个链表,接下来看有没有servlet可以处理该请求,如果有加入进来到链表内,如果没有,则把缺省servlet加入到链表内。

filetr----filter----servlet的链表

context依次去调用该链表内每一个组件的对应方法,filter.doFilter servlet.service,在调用该方法的时候,将这两个对象作为参数传递进去

6.Connector读取response里面的数据,生成HTTP响应报文

Connector{
​	Engine engine
	request
	response
action(){
​	engine.xxx(request,response);
  // 读取response里面的数据
}
}
filter doFilter before
second filter doFilter before
servlet doget
second filter doFilter after
filter doFilter after

使用场景

1.设置编码格式

2.拦截

login.jsp 放行的

info.jsp 而是登录了之后进行放行,没有登录执行拦截

/login 放行

你可能感兴趣的:(Java)