第一个100日计划之 第6天 Servlet006--分发和重定向,监听器

前一篇文章主要总结了servlet上传文件的相关知识,有一个大概的理解,后续总结Struts2和springMVC再进行对比总结。


一、分发ReqestDispatcher

web应用中,把一个请求转发给另外一个servlet处理或者包含另外一个servlet的输出是比较有用的。ReqestDispatcher接口提供这方面机制的API.

1.1 ReqestDispatcher相关方法总结

  • ReqestDispatcher req.ReqestDispatcher(String path):获取ServletContext 中ReqestDispatcher对象,参数path分发servletd的路径,如果这个路径没找到对应的servlet,则返回这个路径内容提供的RequestDispatcher。
  • getNamedDispatcher(String name) :获取指定名称servlet的ReqestDispatcher对象

1.2 include方法

1.2.1 方法介绍

   ReqestDispatcher的include方法,即包含另外一个servlet请求,被包含servlet共享主servlet方法的reqest和response对象,若主servlet中包含输出时,在目标servlet调用service方法之前先输出到页面。

1.2.2 实例

公共的servlet(被转发或者包含的servlet):

package com.david.servlet.dispatcher;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 公共的servlet
 * @author david
 *
 */
@WebServlet("/dispatch/common")
public class CommonServlet extends HttpServlet {
	
	private static final long serialVersionUID = 2440462577828628767L;
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String dsp = (String)req.getAttribute("dispatch");
		System.out.println("分发者传过来的参数:"+dsp);
		resp.getWriter().println("tihs is a common servlet!");
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}

}

 主servlet:

package com.david.servlet.dispatcher;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 演示 dispatcher include方法
 * @author David
 *
 */
@WebServlet("/dispatch/include")
public class DispatcherIncludeServlet extends HttpServlet {
	
	private static final long serialVersionUID = -3012881475963921847L;
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		req.setAttribute("dispatch", "this is  a dispatcher!");
		RequestDispatcher requestDispatcher = req.getRequestDispatcher("/dispatch/common");
		resp.getWriter().println("this is a dispatcher servlet !");
		requestDispatcher.include(req, resp);
		
		
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
}

访问结果:

  

小结:1.包含servlet的时,请求地址并没有发生改变(后续与重定向对比)

        2.主servlet的resp对象输出和commonservlet resp对象输出都输出在页面。

1.3 forword 方法

1.3.1 方法介绍

forward 方法,只有在没有输出提交到向客户端时,通过正在被调用的 servlet 调用,如果响应缓冲区中存在尚未提交的输出数据,这些数据内容必须在目标 servlet 的 service 方法调用前清除。

1.3.2 实例

common部分与include方法公用一个commonservlet.

主servlet:

package com.david.servlet.dispatcher;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 演示Dispatcher forward方法
 * @author David
 *
 */
@WebServlet("/dispatch/forword")
public class DispatcherForwordServlet extends HttpServlet {
	private static final long serialVersionUID = -5505834174796788396L;
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setAttribute("dispatch", "come from DispatcherForwordServlet!");
		resp.getWriter().println("DispatcherForwordServlet!");
		req.getRequestDispatcher("/dispatch/common").forward(req, resp);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
}

访问http://127.0.0.1/s//dispatch/forword

结果:

    

小结:主servlet输出丢失,页面仅仅显示commonservlet输出内容,include和forword方法的主要区别。

二、重定向

当文档移动到新的位置,我们需要向客户端发送这个新位置时,我们需要用到网页重定向。当然,也可能是为了负载均衡,或者只是为了简单的随机,这些情况都有可能用到网页重定向。

HttpServletResponse提供2种重定向的方式: resp.sendRedirect()和resp.setStatus()+resp.setHeader(),不多说直接上实例。

servlet部分:

package com.david.servlet.sendRedirect;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/sendRedirect")
public class SendRedirectWithoutStatus extends HttpServlet {
	
	private static final long serialVersionUID = -208105337891475980L;
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String status = req.getParameter("status");
		if(null==status|| "".equals(status)){
			resp.sendRedirect("https://www.baidu.com/");
		}else{
			resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);//302
			resp.setHeader("Location", "https://www.csdn.net/");
		}
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
}

当访问路径不带status参数时,使用sendRedirect,重定向到百度,当带status使用resp.setStatus()+resp.setHeader()的方式重定向到CSDN。

三、分发器与重定向对比

  • 调用者:

      分发器:request.getRequestDispatcher(“/*”).forward(req,resp)或者inlude(req,resp); 

      重定向:response.sendRedirect(url)

  • 地址栏变化

      分发器:服务器行为,浏览器地址不会改变,共享request和response等对象

     重定向:客户端行为,相当于2次请求,不共享req和resp对象,地址会发生改变

  • 作用范围

    分发器:同一个项目中跳转

    重定向:不仅仅同一个项目,不同服务器之间也可以跳转

四、监听器

4.1 监听器概述

事件机制给 Web 应用开发人员更好地控制 ServletContext、HttpSession 和 ServletRequest 的生命周期,可以更好地代码分解,并在管理 Web 应用使用的资源上提高了效率。Servlet 事件监听器支持在 ServletContext、HttpSession 和ServletRequest 状态改变时进行事件通知。后续web应用种常常使用listener加载配置文件到ServletContext中。

  • ServletContext Events 事件监听
事件类型描述监听接口
生命周期

ServletContext刚刚创建并可应用第一个请求,或者

ServletContext即将销毁

javax.servlet.ServletContextListener
属性改变在 Servlet 上下文的属性已添加、删除、或替换javax.servlet.ServletContextAttributeListener
  • HttpSession  Events监听
事件类型描述监听接口
生命周期会话已创建、销毁或超时javax.servlet.http.HttpSessionListener
属性更改已经在HttpSession上添加、移除、或替换属性javax.servlet.http.HttpSessionAttributeListener
改变IDHttpSession 的 ID 将被改变javax.servlet.http.HttpSessionIdListener
会话迁移HttpSession 已被激活或钝化javax.servlet.http.HttpSessionActivationListener
对象绑定对象已经从HttpSession绑定或解除绑定javax.servlet.http.HttpSessionBindingListener

ServletRequest  Events监听

事件类型描述监听接口
生命周期一个servlet请求已经开始由Web组件处理javax.servlet.ServletRequestListener
更改属性已经在ServletRequest上添加、移除、或替换属性javax.servlet.ServletRequestAttributeListener
异步事件超时、连接终止或完成异步处理javax.servlet.AsyncListener

 

 

 

 

 

4.2 实例

listener:

package com.david.servlet.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyServletContexListener implements ServletContextListener {

	@Override
	public void contextDestroyed(ServletContextEvent sce) {

	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("这是ServletContexListener初始化的时间:"+System.currentTimeMillis());
		//获取上下文对象
		ServletContext servletContext = sce.getServletContext();
		servletContext.setAttribute("test", "1234");
	}

}

servlet:

package com.david.servlet.listener;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/listener")
public class ListenerServlet extends HttpServlet {
	@Override
	public void init() throws ServletException {
		System.out.println("这是servlet初始化的时间:"+System.currentTimeMillis());
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		ServletContext servletContext = req.getServletContext();
		String test = (String) servletContext.getAttribute("test");
		resp.getWriter().write(test);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
}

为了比较加载顺序 创建一个filter:

package com.david.servlet.listener;

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;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

@WebFilter(filterName = "CompareFilter", urlPatterns = "/listener", initParams = {
		@WebInitParam(name = "initFilter", value = "initFilter") })
public class CompareFilter implements Filter {

	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		chain.doFilter(req, res);
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
		String p = config.getInitParameter("initFilter");
		System.out.println("过滤器初始化参数:" + p);
		System.out.println("过滤器初始化时间:" + System.currentTimeMillis());

	}

}

启动服务器并访问:

小结:1.listener和filter是再服务器启动的时候就会初始化

           2.servlet是在第一次接收到请求的时候初始化,当然也可以设置成在服务器启动时就创建该servlet

           3.加载顺序  listener>filter>servlet

五、servlet、filter、listener、interceptor之间对比

5.1概念

  • servlet:servlet是一种运行服务器端的java组件,具有独立与平台和协议的特性,工作在服务器与客户端之间的中间层
  • filter:filter能够在一个请求到达servlet之前预处理用户请求,也可以在离开servlet时处理http响应,在执行servlet之前,首先执行filter程序,并为之做一些预处理工作,基于接口的方式
  • listener:通过listener可以监听web服务器中某一个执行动作,并根据其要求作出相应的响应
  • interceptor:面向切面编程的,常见应用spring aop。(后续详解)

5.2 加载顺序

context- param -> listener -> filter -> servlet 

此处暂时总结如此,后续总结相应框架时详细总结。

参考文档:https://blog.csdn.net/ryo1060732496/article/details/82956326


到此为止,关于Servlet基本知识的总结暂时告一段落,后续遇到比较重要的知识点再继续补充,servlet部分总结总共花费约7天时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值