1.原理
Servlet 的三种方式。
1、实现 Servlet 接口
因为是实现 Servlet 接口,所以我们需要实现接口里的方法。
下面我们也说明了 Servlet 的执行过程,也就是 Servlet 的生命周期。
//Servlet的生命周期:从Servlet被创建到Servlet被销毁的过程
//一次创建,到处服务
//一个Servlet只会有一个对象,服务所有的请求
/*
* 1.实例化(使用构造方法创建对象)
* 2.初始化 执行init方法
* 3.服务 执行service方法
* 4.销毁 执行destroy方法
*/
public class ServletDemo1 implements Servlet {
//public ServletDemo1(){}
//生命周期方法:当Servlet第一次被创建对象时执行该方法,该方法在整个生命周期中只执行一次
public void init(ServletConfig arg0) throws ServletException {
System.out.println("=======init=========");
}
//生命周期方法:对客户端响应的方法,该方法会被执行多次,每次请求该servlet都会执行该方法
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
System.out.println("hehe");
}
//生命周期方法:当Servlet被销毁时执行该方法
public void destroy() {
System.out.println("******destroy**********");
}
//当停止tomcat时也就销毁的servlet。
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
}
2、继承 GenericServlet 类
它实现了 Servlet 接口除了 service 的方法,不过这种方法我们极少用。
public class ServletDemo2 extends GenericServlet {
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
System.out.println("heihei");
}
}
3、继承 HttpServlet 方法
public class ServletDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("haha");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("ee");
doGet(req,resp);
}
}
Filter 过滤器方法
过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:主要是实现这个接口
序号 | 方法 & 描述 |
---|---|
1 | public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。 |
2 | public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。 |
3 | public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。 |
过滤器链也就是chain.dofilter()的代码:类似这种相同匹配模式的过滤器会存在于同一个过滤链中,然后按照初始化的先后顺一次排列,实现逐层过滤。其中filterChain中有个doFilter方法,他的作用是将当前请求转发给过滤链中的下一个过滤器进行过滤,然后将过滤结果,只有等待下一个过滤器执行过滤完成后才能继续执行。该执行过程类似如下图:
如上图,通过过滤链逐层执行过滤就像一层嵌套,一层套一层,如果过滤链中只有一个过滤器(或者执行到最后一个)的话,执行了chain.doFilter()他会直接将请求转发出去,获取request resource资源,因为从始至终都是同一个request和response在传递,所以每次过滤都可以修改请求或返回结果,实现了过滤修改的目的。
1.过滤器实例
package com.runoob.test;
//导入必需的 java 库
import javax.servlet.*;
import java.util.*;
//实现 Filter 类
public class LogFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
// 获取初始化参数
String site = config.getInitParameter("Site");
// 输出初始化参数
System.out.println("网站名称: " + site);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
// 输出站点名称
System.out.println("站点网址:http://www.runoob.com");
// 把请求传回过滤链
chain.doFilter(request,response);
}
public void destroy( ){
/* 在 Filter 实例被 Web 容器从服务移除之前调用 */
}
}
2.过滤器直接返回
当过滤器满足条件的时候,不执行之后的过滤器和web请求的时候,可以不写chain.dofilter(),停止转发
过滤器中我们可以根据 doFilte() 方法中的 request 对象获取表单参数信息,例如我们可以获取到请求的用户名和密码进行逻辑处理,也可以通过 response 对用户做出回应。比如如果验证用户名不正确,禁止用户访问 web 资源,并且向浏览器输出提示,告诉用户用户名或者密码不正确等等;
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
//获取请求信息(测试时可以通过get方式在URL中添加name)
//http://localhost:8080/servlet_demo/helloword?name=123
String name = req.getParameter("name");
// 过滤器核心代码逻辑
System.out.println("过滤器获取请求参数:"+name);
System.out.println("第二个过滤器执行--网站名称:www.runoob.com");
if("123".equals(name)){
// 把请求传回过滤链
chain.doFilter(req, resp);
}else{
//设置返回内容类型
resp.setContentType("text/html;charset=GBK");
//在页面输出响应信息
PrintWriter out = resp.getWriter();
out.print("<b>name不正确,请求被拦截,不能访问web资源</b>");
System.out.println("name不正确,请求被拦截,不能访问web资源");
}
}
大概看下web如何配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.runoob.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>菜鸟教程</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<!-- 类名 -->
<servlet-name>DisplayHeader</servlet-name>
<!-- 所在的包 -->
<servlet-class>com.runoob.test.DisplayHeader</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayHeader</servlet-name>
<!-- 访问的网址 -->
<url-pattern>/TomcatTest/DisplayHeader</url-pattern>
</servlet-mapping>
</web-app>
Listern监听器
1、什么是Java监听器
监听器也叫Listener,是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。
2、Listener接口分类
ServletContext监听器
1.1 ServletContextListener监听ServletContext对象,可以监听到容器的初始化和销毁
1.2 ServletContextAttributeListener监听对ServletContext属性的操作,比如增加、删除、修改(application范围)
HttpSession监听器
2.1> HttpSessionListener监听Session对象,包括了session的创建和销毁。
2.2> HttpSessionAttributeListener监听Session中的属性操作,比如增加、删除、修改(session范围)
2.3> HttpSessionActivationListener监听HTTP会话的active和passivate情况,passivate是指非活动的session被写入持久设备(比如硬盘),active相反。
注意:HttpSessionActivationListener不需要web.xml配置文件
实现了HttpSessionActivationListener接口的 JavaBean 对象可以感知自己被活化和钝化的事件
活化:javabean对象和Session一起被反序列化(活化)到内存中(硬盘到内存);
钝化:javabean对象和Session一起序列化到硬盘中(内存到硬盘);
javabean对象存在Session中,当服务器把session序列化到硬盘上时,如果Session中的javabean对象实现了Serializable接口
那么服务器会把session中的javabean对象一起序列化到硬盘上,javabean对象和Session一起被序列化到硬盘中的这个操作称之为钝化
如果Session中的javabean对象没有实现Serializable接口,那么服务器会先把Session中没有实现Serializable接口的javabean对象移除
然后再把Session序列化(钝化)到硬盘中;
当绑定到 HttpSession对象中的javabean对象将要随 HttpSession对象被钝化之前,
web服务器调用该javabean对象的 sessionWillPassivate方法,
这样javabean对象就可以知道自己将要和 HttpSession对象一起被序列化(钝化)到硬盘中
当绑定到HttpSession对象中的javabean对象将要随 HttpSession对象被活化之后,
web服务器调用该javabean对象的sessionDidActive方法,
这样javabean对象就可以知道自己将要和 HttpSession对象一起被反序列化(活化)回到内存中
2.4> HttpSessionBindingListener监听器:感知Session绑定的事件监听器 ,就是我们常常存储的数据
注意:HttpSessionBindingListener不需要web.xml配置文件
保存在Session域中的对象可以有多种状态:
(1)绑定(session.setAttribute("bean",Object))到Session中;
(2)从Session域中解除(session.removeAttribute("bean"))绑定;
(3)随Session对象持久化到一个存储设备中;
(4)随Session对象从一个存储设备中恢复;
Servlet 规范中定义了两个特殊的监听器接口"HttpSessionBindingListener和HttpSessionActivationListener"
来帮助JavaBean 对象了解自己在Session域中的这些状态: ,
实现这两个接口的类不需要 web.xml 文件中进行注册。
ServletRequest监听器
3.1> ServletRequestListener监听Request对象
3.2> ServletRequestAttributeListener监听Requset中的属性操作
3、Java代码
1.1> ServletContextListener
监听器类代码:
public class ls implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("------------------"+"容器初始化");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("------------------"+"容器销毁");
}
}
web.xml配置代码:
<!-- ServletContext对象监听器 -->
<listener>
<listener-class>cn.itcast.erp.listener.servletContext.ServletContextListener1</listener-class>
</listener>
1.2> ServletContextAttributeListener
监听器类代码:
package com.xxx.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
//把一个属性存入application范围时触发该方法
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
ServletContext application=event.getServletContext();
//获取添加的属性名和属性值
String name=event.getName();
Object value=event.getValue();
System.out.println(application+"范围内添加了名为"+name+"值为"+value+"的属性");
}
//把一个属性从application范围删除时触发该方法
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
ServletContext application=event.getServletContext();
//获取被删除的属性名和属性值
String name=event.getName();
Object value=event.getValue();
System.out.println(application+"范围内名为"+name+"值为"+value+"的属性被删除了");
}
//替换application范围内的属性时触发该方法
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
ServletContext application=event.getServletContext();
//获取被替换的属性名和属性值
String name=event.getName();
Object value=event.getValue();
System.out.println(application+"范围内"+name+"值为"+value+"的属性被替换了");
}
}
2.1>HttpSessionListener
监听器类代码:
public class HttpSessionListener1 implements HttpSessionListener{
/**
* 通知会话已创建。
* session创建之后调用
*/
@Override
public void sessionCreated(HttpSessionEvent event) {
System.out.println("session创建之后");
HttpSession session = event.getSession();
}
/**
* 通知会话即将失效。
* session销毁之前调用
*/
@Override
public void sessionDestroyed(HttpSessionEvent event) {
System.out.println("session销毁之前");
HttpSession session = event.getSession();
}
}
web.xml配置代码:
<!-- HttpSession对象监听器 -->
<listener>
<listener-class>cn.itcast.erp.listener.session.HttpSessionListener1</listener-class>
</listener>
2.2> HttpSessionAttributeListener
监听器类代码:
public class HttpSessionAttributeListener1 implements HttpSessionAttributeListener{
/**
* 通知某个属性已被添加到会话中。 在添加属性后调用。
*/
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("session添加属性后调用");
HttpSession session = event.getSession();
String name = event.getName();
Object value = event.getValue();
System.out.println("被添加到session中的属性:" + "key=" + name + " ,value=" + value);
}
/**
* 通知某个属性已从会话中删除。 在属性被删除后调用。
*/
@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("session删除属性后调用");
HttpSession session = event.getSession();
String name = event.getName();
Object value = event.getValue();
System.out.println("被删除的session中的属性:" + "key=" + name + " ,value=" + value);
}
/**
* 在会话中通知属性已被替换。 在属性被替换后调用。
*/
@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("session替换属性后调用");
HttpSession session = event.getSession();
String name = event.getName();
Object value = event.getValue();
System.out.println("被替换的session中的属性:" + "key=" + name + " ,替换之前的value=" + value);
}
}
2.3> HttpSessionActivationListener
监听器类代码(不需要配置web.xml):
public class HttpSessionActivationListener1 implements HttpSessionActivationListener {
/**
* 通知该会话即将被钝化。
* 当前javaBean绑定到session中钝化之前
*/
@Override
public void sessionWillPassivate(HttpSessionEvent event) {
System.out.println("session钝化之前");
HttpSession session = event.getSession();
}
/**
* 通知该会话刚刚被激活。
* 当前javaBean绑定到session中活化之后
*/
@Override
public void sessionDidActivate(HttpSessionEvent event) {
System.out.println("session活化之后");
HttpSession session = event.getSession();
}
}
2.4> HttpSessionBindingListener
监听器类代码(不需要配置web.xml):
public class HttpSessionBindingListener1 implements HttpSessionBindingListener {
/**
* 通知对象它正在被绑定到会话并标识会话。(还未绑定)
*/
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("当前对象正在绑定到session中,还未绑定");
HttpSession session = event.getSession();
String name = event.getName();
Object value = event.getValue();
System.out.println("将要被绑定到session中的key值:" + name + "value值:" + value);
System.out.println("value值是否是当前对象:" + (value == this));//true
Object valueNow = session.getAttribute(name);
System.out.println("valueNow:" + valueNow);//null,还未绑定
}
/**
* 通知对象它正在从会话中解除绑定并标识会话。(还未解除绑定)
*/
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("当前对象它正在从会话中解除绑定");
HttpSession session = event.getSession();
String name = event.getName();
Object value = event.getValue();
System.out.println("将要解除绑定session中的key值:" + name + "value值:" + value);
System.out.println("value值是否是当前对象:" + (value == this));//true
Object valueNow = session.getAttribute(name);
System.out.println("valueNow:" + valueNow);//null,还未解除绑定
}
}
2.5还有
3.1> ServletRequestListener监听Request对象
3.2> ServletRequestAttributeListener监听Requset中的属性操作
方法与ServletContext类似,实现接口不同而已,不再描述。
2.内容
1.注册Servlet
(1)使用ServletRegistrationBean注册
使用ServletRegistrationBean注册只需要在@Configuration类中加入即可,例如以下代码:
@Bean
public ServletRegistrationBean myServlet() {
ServletRegistrationBean myServlet = new ServletRegistrationBean();
myServlet.addUrlMappings("/servlet");
myServlet.setServlet(new MyServlet());
return myServlet;
}
(2)使用@WebServlet
使用@WebServlet注册,需要在Servlet类上使用该注解即可,但是需要在@Configuration类中使用Spring Boot提供的注解@ServletComponentScan扫描注册相应的Servlet。
2.注册Filter
(1)使用FilterRegistrationBean注册
使用FilterRegistrationBean注册Filter,只需要在@Configuration类中加入即可,例如以下代码:
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean myFilter = new FilterRegistrationBean();
myFilter.addUrlPatterns("/*");
myFilter.setFilter(new MyFilter());
return myFilter;
}
(2)使用@WebFilter
使用@WebFilter注册,需要在Filter类上使用该注解即可,但是需要在@Configuration类中使用Spring Boot提供的注解@ServletComponentScan扫描注册相应的Filter。
3.注册Listener
(1)使用ServletListenerRegistrationBean注册
使用ServletListenerRegistrationBean注册Listener只需要在@Configuration类中加入即可,例如以下代码:
@Bean
public ServletListenerRegistrationBean<MyListener> myServletListener() {
ServletListenerRegistrationBean<MyListener> myListener = new ServletListenerRegistrationBean<MyListener>();
myListener.setListener(new MyListener());
return myListener;
}
(2)使用@WebListener
使用@WebListener注册,需要在Filter类上使用该注解即可,但是需要在@Configuration类中使用Spring Boot提供的注解@ServletComponentScan扫描注册相应的Listener。
3.总结
主要是web上的servlet、filter、listen,可以web配置、java配置、注解配置,而注解更加简单,不过记得要加入扫描器。监听器用处可以说较大,比如session的监听,可以做某些清楚工作。
转载资料:
http://www.runoob.com/servlet/servlet-writing-filters.html
http://www.runoob.com/servlet/servlet-intro.html
https://blog.csdn.net/menghuanzhiming/article/details/79042182