前一篇文章主要总结了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 |
改变ID | HttpSession 的 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天时间。