【Java之Web组件】

Web组件

最开始,ee规范中只有servlet一个组件。

后来,又出现了两个组件,listener、filter

listener:监听器()

filter:过滤器(拦截)

Listener

web访问过程中的监听器

被监听者:ServletContext对象

监听者:自己编写了一个监听器

监听事件:对象的创建和销毁

触发行为:调用自己写的监听器对应的方法

作用:主要负责监听ServletContext对象的创建和销毁,一般存放全局性的代码

使用

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

2.注册当前监听器(web.xml 注解)

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

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

原理

底层维护了一个接口,通过不同的子实现来调用不同的方法

class ServletContext {

	List<ServletContextListener> listeners;
	
	//注册该listener,tomcat会调用
	add(ServletContextListener listener){
		listeners.add(listener);
	}
	
	init(){
		listeners.for{listener.contextInitialized()}
	}
	
	destroy(){
		listeners.for{listener.contextDestroyed()}
	}

}

Filter

介绍

​ 过滤器,主要的作业是对请求和响应对象进行检查和修改。—>ServletContext

​ 设置编码格式

​ 可以实现对页面的拦截和放行

与过滤器关联的Servlet

使用

​ 1.编写一个类实现Filter接口

​ 2.注册该Filter

filter如何和servlet关联

最简单的方式就是通过url-pattern进行关联,即把servlet的url-pattern直接赋值给filter即可

filter默认情况下执行的是拦截操作,如果需要放行,必须要加如下代码:

filterChain.doFilter(servletRequest, servletResponse);//底层使用递归调用

filter url-pattern的不同于servlet之处

1.filter可以设置和servlet相同的url-pattern

*2.filter设置/*,并且设置/ 还是很有必要的

3.filter不可以设置/

4.如果有多个filter,设置相同的url-pattern,那么也是允许的

多个filter的执行先后顺序

1.如果是web.xml,按照filter-mapping声明的先后顺序

<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2.如果是注解,那么按照类名首字母ASCII先后顺序,即英文字母的顺序

流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请求的去程,只执行filterChain.doFilter上面的代码

返程只执行下面的代码

请求的完整执行流程

访问http://localhost/app/1.html

以访问http://localhost/app/1.html为例

1.域名解析(浏览器缓存–操作系统缓存–hosts缓存–dns服务器),TCP三次握手建立连接,浏览器生成请求报文经过tcp层拆包打上标签经过ip层打上端口号和目标ip,从链路层发出去在网上中转传输到目标主机

2.到达服务器后被一直监听80端口号的HTTP/1.1 Connector接收到,将其解析为request对象并生成一个response对象

3.Connector将两个对象下发给Engine,Engine进一步下发交给Host

4.Host的职责是挑选一个叫/app的应用,如果找到就将两个对象交给该应用,如果找不到就交给ROOT应用,如果ROOT应用中都没有,那就404

5.此时有效的路径就是/1.html,查找有没有filter可以处理该请求,如果有就将该filter加入组件执行的链表中,如果有多个按照先后顺序来排列,配置在web.xml文件中就按照文件的顺序执行,使用注解就按照首字母的ASCII码大小顺序执行

6.进一步查看有没有servlet可以处理该请求,如果没有就交给缺省的servlet,此时要看servlet有没有重写,如果重写了那就交给自己重写的处理,如果没有重写就交给默认的处理,当做静态资源访问,如果此时没有该资源,就抛出404

7.依次调用链表上的每一个组件,调用Filter的doFilter方法以及servlet的service方法,方法执行时需要传入request和response这两个参数

8.全部执行完毕后,Connector读取response里面的数据生成响应报文,再依次通过tcp,ip,链路层出去发送到客户端,客户端再进行解析

案例

登陆注销案例,加入拦截的功能,如果没有登陆则直接返回登陆页面

package com.fh.filter.login;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/user1/*")
public class UserServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        String op = requestURI.replace(request.getContextPath() + "/user1/", "");
        //将前面的部分替换为空白,取出具体的详情页面的部分,根据不同的方法进行分发处理
        if ("loginxx".equals(op)){
            login(request,response);
        }
    }

    private void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //具体的登陆的处理逻辑
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        HttpSession session = request.getSession();
        session.setAttribute("username",username);
        response.getWriter().println("登陆成功,进入个人主页");
        response.setHeader("refresh","2;url="+request.getContextPath()+"/user1/infoxx");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //刷新页面是get请求
        String requestURI = request.getRequestURI();
        String op = requestURI.replace(request.getContextPath() + "/user1/", "");
        if ("infoxx".equals(op)){
            info(request,response);
        }else if ("logoutxx".equals(op)){
            logout(request,response);
        }

    }

    private void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //处理注销的逻辑
        request.getSession().invalidate(); //清除session实现注销,服务器没有保存此客户端的数据了
        response.getWriter().println("注销成功,即将跳回登陆页面");
        response.setHeader("refresh","2;url="+request.getContextPath()+"/login5.html");
    }

    private void info(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //具体的详情页面的逻辑
        HttpSession session = request.getSession();
        Object username = session.getAttribute("username");
        response.getWriter().println("欢迎"+username+"<a href='"+request.getContextPath()+"/user1/logoutxx"+"'>点我注销</a>");
    }
}
package com.fh.filter.login;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*")
public class AuthFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        if (auth(request)){
            //这里的主要逻辑就是如果是需要登陆的页面,并且用户没有登陆,那就进行拦截
            //反之如果页面不需要登陆,或者需要登陆且用户登陆了,就不拦截
            Object username = request.getSession().getAttribute("username");
            //主要看username是否为空,如果当前客户端的session对象中存放了username,那么就说明登陆了,反之则不行
            if (username==null){
                response.getWriter().println("你还没有登陆!即将跳回登陆页面");
                response.setHeader("refresh","2;url="+request.getContextPath()+"/login5.html");
                return;//一定要return,否则继续向下执行就放行了
            }
        }
        filterChain.doFilter(request,response);
    }

    private boolean auth(HttpServletRequest request) {
        //校验是否是需要验证登陆的页面
        String s = request.getContextPath() + "/user1/infoxx";
        if (s.equals(request.getRequestURI())){
            //uri是当前访问到的页面,如果与我们预设好的相等,那就说明需要登陆,返回true
            return true;
        }
        return false;
    }


    @Override
    public void destroy() {

    }
}
  • 14
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值