• JavaWeb——Servlet转发与重定向的区别,过滤器与监听器


    转:

    JavaWeb——Servlet转发与重定向的区别,过滤器与监听器
    原创 等一次另眼相看 最后发布于2019-04-10 19:12:21 阅读数 121 收藏
    展开

    文章目录

    转发与重定向
    本质区别
    过滤器Filter
    过滤器可以做什么
    过滤器示例——处理中文乱码
    filter的三种典型应用:
    监听器Listener
    监听器示例——统计在线人数

    转发与重定向

    https://blog.csdn.net/meiyalei/article/details/2129120

    Servlet中转发:

    // 转发NewServelt
    request.getRequestDispatcher("NewServelt").forword(request,response);

    1
    2

    Servelt重定向:

    // 重定向到NewServlet
    response.sendRedirect("NewServlet");

    1
    2

    jsp页面中转发:

    <jsp:forword page = "NewServelt">

    1

    jsp页面重定向:

    <%response.sendRedirect("new.jsp");%>

    1

    本质区别

    转发是服务器行为,重定向是客户端行为。

    转发过程:客户浏览器发送http请求----》web服务器接受此请求–》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。

    重定向过程:客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器–》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。

    过滤器Filter

    过滤器是Servlet中最令人激动的特性之一,当浏览器发送请求给服务器时,服务器会先执行过滤器,然后才访问web资源。服务器响应请求,在web资源抵达浏览器之前,也会途径过滤器。
    过滤器可以做什么

    你可以把过滤器想象成一张过滤网,服务器与浏览器的信息交互都要经过过滤器以保证满足标准。使用过滤器可以过滤一些敏感字符串,可以避免中文乱码,可以进行权限验证(比如规定只有带session和cookie的浏览器才可以访问资源)等等。
    过滤器的出现使得一些棘手的问题得以解决,最通俗的体现就在于处理中文乱码,我们都知道,只有使用utf-8编码才能使得全世界各地的字符得以正确显示。不使用过滤器的话我们就需要在所有的servlet和jsp中对编码加以声明,代码的重复率相当高。
    过滤器示例——处理中文乱码

    只要java类实现了Filter接口就可以成为过滤器。
    一个标准的过滤器:

    新建Servlet实现Filter接口,重写其方法:

    package com.xx.filter;

    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;

    // 实现Filter接口就可以称之为过滤器
    public class EncodingFilter implements Filter {
    // 构造方法
    public EncodingFilter() {
    // TODO Auto-generated constructor stub
    }

    // 销毁方法,与Servlet中的destory方法类似
    public void destroy() {
    // TODO Auto-generated method stub
    }

    // doFilter方法,在这里实现过滤器功能
    // 它有三个参数(ServletRequest,ServletResponse,FilterChain)
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    // 我们把处理中文乱码的代码放在这里就可以了
    request.setCharacterEncoding("utf-8");
    response.setContentType("text/html;charset=utf-8");

    // pass the request along the filter chain
    // 在Java中使用了链式结构来管理过滤器。把所有的过滤器都放在FilterChain里边
    // 如果符合条件,就执行下一个过滤器(如果没有过滤器了,就执行目标资源)。
    chain.doFilter(request, response);
    }

    // 初始化方法,和destory方法都只执行一次
    public void init(FilterConfig fConfig) throws ServletException {
    // TODO Auto-generated method stub
    }

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43

    Filter部署

    和Servlet一样,过滤器需要部署在服务器上:
    第一种方式:在web.xml文件中部署

    <filter>
    <display-name>EncodingFilter</display-name>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>com.xx.filter.EncodingFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    1
    2
    3
    4
    5
    6
    7
    8
    9

    <filter>用于注册过滤器
    <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空
    <filter-class>用于指定过滤器的完整的限定类名
    <filter-mapping>用于设置一个Filter所负责拦截的资源
    <filter-name>子元素用于设置filter的注册名称。该值必须是在元素中声明过的过滤器的名字
    一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
    <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
    <servlet-name>指定过滤器所拦截的Servlet名称。
    <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截。

    dispatcher小结
    <dispatcher>子元素可以设置的值及其意义:

    REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
    INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
    FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
    ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

    filter的三种典型应用:

    可以在filter中根据条件决定是否调用chain.doFilter(request, response)方法,即是否让目标资源执行
    在让目标资源执行之前,可以对requestresponse作预处理,再让目标资源执行
    在目标资源执行之后,可以捕获目标资源的执行结果,从而实现一些特殊的功能

    监听器Listener

    监听器其实就是一个实现了特定接口普通java程序,这个程序专门用来监听一个java对象的方法调用或者属性改变,当被监听的对象的事件发生后,监听器就会立即捕捉到,并做以响应的处理。
    我们把被监听的对象称作事件源。在Servlet规范中定义了多种类型的监听器,我们可以使用监听器来监听 ServletContext,HttpSession和HttpServletRequest这三个作用域对象。监听的内容分为:监听域对象的创建和销毁,监听域对象的属性变化
    ServletContext HttpSession HttpServletRequest
    域对象的创建和销毁 ServeltContextListener HttpSessionListener ServeltRequestListener
    域对象属性的变化 ServeltContextAttributeListener HttpSessionAttributeListener ServeltRequestAttributeListener

    我们可以根据实际要求去实现不同的接口以监听目标事件源。

    监听器的部署,写在web.xml文件当中:

    <listener>
    <listener-class>com.xx.listener.CountOnlineUserListener</listener-class>
    </listener>

    1
    2
    3

    监听器示例——统计在线人数

    我们先来新建一个简单的登录页面:

    <html>
    <head>
    <meta charset="UTF-8">
    <style type="text/css">
    body{text-align:center;}
    span{ color:red; font-size:200% }
    hr{ margin-bottom:30px }
    </style>
    </head>
    <body>
    <span> 登录 </span>
    <hr color="red"/>
    <form action="LoginServlet" method="post">
    <table border="1" bordercolor="blue" width="40%" cellspacing="0" align="center">
    <tr>
    <td>用户名:</td>
    <td><input type="text" name="username"/></td>
    </tr>
    <tr>
    <td>密码:</td>
    <td><input type="password" name="password"/></td>
    </tr>
    <tr align="center">
    <td colspan="2">
    <input type="submit" value="登陆"/> <input type="reset" value="重置"/>
    </td>
    </tr>
    </table>
    </form>
    </body>
    </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

    看下效果:
    在这里插入图片描述
    现在来新建LoginServlet:

    package com.xx.servlet;

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

    /**
    * Servlet implementation class LoginServlet
    */
    public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
    * @see HttpServlet#HttpServlet()
    */
    public LoginServlet() {
    super();
    // TODO Auto-generated constructor stub
    }

    /**
    * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
    * response)
    */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // 模拟登陆后在首页显示当前在线人数
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    // 拿到用户输入的用户名和密码后,我们自然是拿去和数据库中的数据做校验
    // 我们假设校验成功,然后跳转到首页页面
    response.sendRedirect("IndexServlet");
    }

    /**
    * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
    * response)
    */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
    }

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    这是IndexServlet:

    package com.xx.servlet;

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

    /**
    * Servlet implementation class Index
    */
    public class Index extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
    * @see HttpServlet#HttpServlet()
    */
    public Index() {
    super();
    // TODO Auto-generated constructor stub
    }

    /**
    * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
    * response)
    */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    response.setContextType("text/html;charset=utf-8");
    HttpSession session = request.getSession();
    response.getWriter().println("当前在线人数是:" + session.getServletContext().getAttribute("count"));
    }

    /**
    * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
    * response)
    */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
    }

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46

    监听器来监听session:

    package com.xx.listener;

    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;

    /**
    * Application Lifecycle Listener implementation class CountOnlineUserListener
    *
    */
    public class CountOnlineUserListener implements HttpSessionListener {

    /**
    * Default constructor.
    */
    public CountOnlineUserListener() {
    // TODO Auto-generated constructor stub
    }

    /**
    * @see HttpSessionListener#sessionCreated(HttpSessionEvent)
    */
    public void sessionCreated(HttpSessionEvent se) {
    // TODO Auto-generated method stub
    // 有用户登录,session就会被创建
    HttpSession session = se.getSession()
    // ServletContext的作用范围:整个web应用范围内,我们就用它来存在线人数
    Integer count = (Integer)session.getServletContext().getAttribute("count");
    // 设置session的有效期
    session.setMaxInactiveInterval(300);
    // 第一个人登陆,此时count应该为null,且count>=0
    if (count == null || count <= 0) {
    session.getServletContext().setAttribute("count", 1);
    } else {
    session.getServletContext().setAttribute("count", count + 1);
    }
    }

    /**
    * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
    */
    public void sessionDestroyed(HttpSessionEvent se) {
    // TODO Auto-generated method stub
    // session失效了,意味着这个人下线了,我们把count-1
    Integer count = (Integer) se.getSession().getServletContext().getAttribute("count");
    se.getSession().getServletContext().setAttribute("count", count - 1);

    }

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50

    这样就完成了对session的监听,如果用户从浏览器登录的话,服务器就会自动创建session,那么这边就可以监听到,并且给count+1,当session被销毁后,就会给count-1。
    ————————————————
    版权声明:本文为CSDN博主「等一次另眼相看」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_44238142/java/article/details/89034560

  • 相关阅读:
    【C#】工具类-FTP操作封装类FTPHelper
    网盘搜索网站
    在线服务
    Windows下安装NTP服务器
    vue 组件间的传值 + 路由守卫
    功能6 -- 选项卡数据缓存
    vue2.0/3.0
    vuex
    mySql笔记
    Typescript
  • 原文地址:https://www.cnblogs.com/libin6505/p/12674131.html
Copyright © 2020-2023  润新知