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

转发与重定向

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

  • Servlet中转发:
// 转发NewServelt
request.getRequestDispatcher("NewServelt").forword(request,response);
  • Servelt重定向:
// 重定向到NewServlet
response.sendRedirect("NewServlet");
  • jsp页面中转发:
<jsp:forword page = "NewServelt">
  • jsp页面重定向:
<%response.sendRedirect("new.jsp");%>

本质区别

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

转发过程:客户浏览器发送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
	}

}

  • 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>
  • <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的三种典型应用:

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

监听器Listener

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

ServletContextHttpSessionHttpServletRequest
域对象的创建和销毁ServeltContextListenerHttpSessionListenerServeltRequestListener
域对象属性的变化ServeltContextAttributeListenerHttpSessionAttributeListenerServeltRequestAttributeListener

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

  • 监听器的部署,写在web.xml文件当中:
  <listener>
    <listener-class>com.xx.listener.CountOnlineUserListener</listener-class>
  </listener>

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

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

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

看下效果:
在这里插入图片描述
现在来新建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);
	}

}

这是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);
	}

}

监听器来监听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);

	}

}

这样就完成了对session的监听,如果用户从浏览器登录的话,服务器就会自动创建session,那么这边就可以监听到,并且给count+1,当session被销毁后,就会给count-1。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值