第六节、Servlet进阶API、过滤器与监听器

过滤器和监听器是Servlet规范里面的两个高级特性,过滤器的作用就是通过对request、response的修改实现特定的功能,例如请求数据字符编码、IP地址过滤、异常过滤、用户身份认证等。监听器的作用就是监听Web程序中正在进行的程序,根据发生的时间做出特定的响应。

Servlet进阶API

在Web容器启动后,通过加载web.xml文件读取Servlet的配置信息,实例化Servlet类,并且为每个Servlet配置信息产生唯一的一个ServletConfig对象。在运行Servlet时,调用Servlet的接口init()方法,将产生的ServletConfig作为参数传入Servlet中。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

应用程序事件与监听器

在这里插入图片描述

ServletContext事件、监听器

当Web应用程序启动时,会自动开始监听,首先调用的是contextInitialized()方法,并传入ServletContextEvent参数。在Web应用关闭时,会自动调用contextDestroyed()方法,同样传入ServletContextEvent参数。可以在contextInitialized()方法中实现Web应用的数据库连接、读取应用程序设置等;在contextDestroyed()中设置数据库资源的释放。

package com.shore;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;

import org.apache.log4j.Logger;


@WebListener
//给当前文件的路径设置为根目录下的GetReaderBody2
public class MyServletContextListener implements ServletContextListener{
    
    
	private static Logger log = Logger.getLogger("MyServletContextListener");
	public void contextInitialized(ServletContextEvent sce) {
    
    
		//通过ServletContextEvent获得ServletContext对象
		ServletContext context = sce.getServletContext();
		String name = context.getInitParameter("user_name");
		log.debug("初始化参数name的值"+name);
		log.debug("Tomcat正在启动中......");
	}
	
	public void contextDestroyed(ServletContextEvent sce) {
    
    
		log.debug("Tomcat正在关闭中......");
	}
}

ServletRequestAttributeListener 被称为“ServletContext属性监听器”,可以用来监听Application属性的添加、移除和替换时相应的动作事件。

public void attributeAdded(ServletRequestAttributeEvent arg0) {
    
    
log.debug("加入一个request范围的属性,名称为:"+
arg0.getName()+",其值为:"+arg0.getValue());
}
public void attributeRemoved(ServletRequestAttributeEvent arg0) {
    
    
log.debug("移除一个request范围的属性,名称为:"+arg0.getName());
}
public void attributeReplaced(ServletRequestAttributeEvent arg0) {
    
    
log.debug("修改一个request范围的属性,名称为:"+
arg0.getName()+",修改前的值为:"+arg0.getValue());

HttpSession事件监控器

与HttpSession有关的监听器有5个:HttpSessionIdListener、HttpSessionListener、HttpSessionAttributeListener、HttpSessionBindingListener、HttpSessionActivationListener。

HttpSessionIdListener用来监听Session ID的变化。当Session ID发生变化时,会触发sessionIDChange()方法,并传入HttpSessionEvent和oldSessionId参数,可以使用HttpSessionEven中的getSession().getId()获取新的session ID,oldSessionId代表改变之前的session ID。

HttpSessionListener是“HttpSession生命周期监听器”,可以用来监听HttpSession对象初始化或者结束时相应的动作事件。当HttpSession对象初始化或者结束前,会自动调用sessionCreated()方法和sessionDestroyed()方法,并传入HttpSessionEven参数,可以通过HttpSessionEven的getSession()方法取得HttpSession对象。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML>
<html>
  <head>
    <title>用户登录</title>
  </head>
  
  <body>
  	   <p>用户登录</p>
  	   <form action="<%=path%>/<%--servletConfigDemo--%>Login.do" method="post">
  	        <table border="1" width="250px;">
  	           <tr>
  	               <td width="75px;" >用户名:</td>
  	               <td ><input name="userId"/></td>
  	           </tr>
  	           <tr>
  	               <td width="75px;">&nbsp;&nbsp;码:</td>
  	               <td ><input name="passwd" type="password"/></td>
  	           </tr>
  	           <tr>
  	               <td colspan="2">
  	                   <input type="submit" value="提交"/>&nbsp;&nbsp;
  	                   <input type="reset" value="重置"/>
  	               </td>
  	           </tr>
  	        </table>
  	   </form>
  </body>
</html>
package com.shore;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet(
		urlPatterns = {
    
     "/Login.do" }, 
		loadOnStartup = 0, 
		name = "Login", 
		displayName = "demo", 
		initParams = {
    
     
			@WebInitParam(name = "success", value = "success.jsp") 
		}
)
public class Login extends HttpServlet {
    
    

	Map<String, String> users;

	public Login() {
    
    
		users = new HashMap<String, String>();
		users.put("zhangsan", "123456");
		users.put("lisi", "123456");
		users.put("wangwu", "123456");
		users.put("zhaoliu", "123456");
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
    
    
		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
    
    
		request.setCharacterEncoding("UTF-8");
		String userId = request.getParameter("userId");
		String passwd = request.getParameter("passwd");
		//匹配用户名与密码,如果一致记录加一
		if (users.containsKey(userId) && users.get(userId).equals(passwd)) {
    
    
			request.getSession().setAttribute("user", userId);
			request.getSession().setAttribute("count",MyHttpSessionListener.getCount());
		}
		String success = getInitParameter("success");
		response.sendRedirect(success);
	}
}
package com.shore;

import jakarta.servlet.annotation.WebListener;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;

@WebListener
public class MyHttpSessionListener implements HttpSessionListener{
    
    

	private static int count;//统计数
	
	public static int getCount() {
    
    
		return count;
	}
 
	public void sessionCreated(HttpSessionEvent se) {
    
    
		MyHttpSessionListener.count++;
	}

	public void sessionDestroyed(HttpSessionEvent se) {
    
    
		MyHttpSessionListener.count--;
	}

}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
%>
<!DOCTYPE HTML>
<html>
  <head>
    <title>登录成功界面</title>
  </head>
  <body>
       <h3>目前在线人数为:${sessionScope.count}</h3>
       <h4>欢迎您:${sessionScope.user}</h4>
       <a href="<%=path%>/logout.do?userId=${sessionScope.user}">注销</a>
  </body>
</html>

在这里插入图片描述
在这里插入图片描述

HttpSessionAttributeListener是“HttpSection属性改变监听器”,可以用来监听HttpSession对象加入属性、移除属性或者替换属性时响应的动作事件。
HttpSessionBindingListener是“HttpSection对象绑定监听器”,可以用来监听HttpSession中设置成HttpSession属性或者从HttpSession中移除时得到session通知。
HttpSessionActivationListener是“HttpSection对象转移监听器”,可以用来实现它对同一会话在不同的JVM中转移。

HttpServletRequest事件、监听器

HttpServletRequest有关的监听器有两个:ServletRequestListener、
ServletRequestAttributeListener。
ServletRequestListener是“Request生命周期监听器”,可以用来监听Request对象初始化或者结束时响应的动作事件。在request对象初始化或者结束前,会自动调用requestInitialized()和requestDestroyed()方法。
ServletRequestAttributeListener是“Request属性改变监听器”,可以用来监听Request对象加入属性、移除属性或者替换属性时响应的动作事件。

过滤器

在Web应用程序中,它即可以拦截过滤浏览器的请求,也可以改变对浏览器的响应。
在这里插入图片描述
请求封装器:是指利用HttpServletRequestWrapper类将请求中的内容进行同意的修改,例如:修改请求字符编码、替换字符、权限验证等。

package com.shore;
import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
@WebFilter(
		asyncSupported = true,
		description = "字符编码过滤器",
		filterName = "encodingFilter",
		urlPatterns = {
    
     "/*" },
		initParams = {
    
    
			@WebInitParam(name = "encoding", value = "UTF-8")
		}
	)
public class EncodingFilter implements Filter{
    
    
	private static Logger log = Logger.getLogger("EncodingFilter");
	private String encoding=null;
	private String filterName="";
	public void init(FilterConfig filterConfig) throws ServletException {
    
    
		//通过filterConfig获得初始化中的编码值
		encoding = filterConfig.getInitParameter("encoding");
		filterName = filterConfig.getFilterName();
		if(encoding==null||"".equals(encoding)){
    
    
			encoding="UTF-8";
		}
		log.debug("获得编码值");
	}
	
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
    
    
		//分别对请求和响应进行编码设置
		HttpServletRequest req = (HttpServletRequest)request;
		log.debug("请求被"+filterName+"过滤");
		//上述编码过滤器对于post请求是没有问题的,但是对于get请求获取中文参数时还是会出现乱码问题。基于这种情况
		//可以到请求封装器HttpServletRequestWrapper包装请求,将字符转换的工作添加到getParameter()方法中
		//这样就可以对请求的参数进行统一的转换
		if("GET".equals(req.getMethod())){
    
    
			req = new RequestEncodingWrapper(req,encoding);
		}else{
    
    
			req.setCharacterEncoding(encoding);
		}
		response.setContentType("text/html;charset="+encoding);
		//传输给过滤器过滤
		chain.doFilter(req, response);
		log.debug("响应"+filterName+"过滤");
	}
	public void destroy() {
    
    
		log.debug("请求销毁");
	}
}
package com.shore;
import java.io.UnsupportedEncodingException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
public class RequestEncodingWrapper extends HttpServletRequestWrapper{
    
    
	private String encoding="";
	public RequestEncodingWrapper(HttpServletRequest request) {
    
    
		//必须调用父类构造方法
		super(request);
	}
	public RequestEncodingWrapper(HttpServletRequest request,String encoding) {
    
    
		//必须调用父类构造方法
		super(request);
		this.encoding = encoding;
	}
	//重新定义getParameter方法
	public String getParameter(String name){
    
    
		String value = getRequest().getParameter(name);
		try {
    
    
			//将参数值进行编码
			if(value!=null&&!"".equals(value))
				value = new String(value.trim().getBytes("ISO-8859-1"), encoding);
		} catch (UnsupportedEncodingException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return value;
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

响应封装器:响应封装器是指利用HttpServletResponseWrapper类将响应中的内容进行统一修改,例如压缩输出内容、替换输出内容等。

异步处理

在这里插入图片描述
对于每个请求,该Servlet会取得异步信息AsyncContext,同时释放占用内存、延迟响应,然后启动AsyncRequest对象定义的线程,在该线程中进行业务处理,等业务处理完成后,输出页面信息并调用AsyncContext的complete()方法表示异步完成。

package com.shore;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import jakarta.servlet.AsyncContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet(
	asyncSupported = true, 
	urlPatterns = {
    
     "/asyncdemo.do" }, 
	name = "myAsyncServlet"
)
public class MyAsyncServlet extends HttpServlet {
    
    
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
    
    
		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
    
    
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		out.println("开始时间" + sdf.format(new Date()) + " <br/> ");
        out.flush();
        //在子线程中执行业务调用,并由其负责输出响应,主线程推出
        AsyncContext asyncContext = request.startAsync(request,response);
        asyncContext.setTimeout(900000000);//设置最大超时时间
        new Thread(new Executor(asyncContext)).start();
        out.println("结束时间" + sdf.format(new Date())+ " <br/> ");
        out.flush();
	}
	//内部类
	public class Executor implements Runnable {
    
    
	    private AsyncContext ctx = null;
	    public Executor(AsyncContext ctx){
    
    
	        this.ctx = ctx;
	    }
	    public void run(){
    
    
	        try {
    
    
	            //等待20秒以模拟业务方法的执行
	            Thread.sleep(20000);
	            PrintWriter out = ctx.getResponse().getWriter();
	            out.println("业务处理完毕的时间" + sdf.format(new Date()) + " <br/> ");
	            out.flush();
	            ctx.complete();
	        } catch (Exception e) {
    
    
	            e.printStackTrace();
	        }
	    }
	}
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42148307/article/details/120075483