Java Web之三 Servlet Filter Listener

Servlet

1.什么是Servlet

Java Servlet是和平台无关的服务器端组件,它运行在Servlet容器中(如Tomcat Servlet容器负责Servlet和客户的通信以及调用Servlet的方法)。

Servlet可完成如下功能:

创建并返回基于客户请求的动态HTML页面

创建可嵌入到现有HTML页面中的部分HTML页面

与其他服务器资源(java程序、数据库)进行通信

2.Servlet的HelloWorld

(1)新建一个java类实现Servlet

public class HelloServlet implements Servlet{
		@Override
		public void init(ServletConfig config) throws ServletException {
			System.out.println("init");
		}

		@Override
		public ServletConfig getServletConfig() {
			System.out.println("getServletConfig");
			return null;
		}

		@Override
		public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
			System.out.println("service");
		}

		@Override
		public String getServletInfo() {
			System.out.println("getServletInfo");
			return null;
		}

		@Override
		public void destroy() {
			System.out.println("destroy");
		}
	}	</span>
(2)web.xml中注册和映射

	<?xml version="1.0" encoding="UTF-8"?>
	<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
		<servlet>
			<servlet-name>helloServlet</servlet-name>
			<servlet-class>com.ithings.servlet.HelloServlet</servlet-class>
		</servlet>
		<servlet-mapping>
			<servlet-name>helloServlet</servlet-name>
			<url-pattern>/hello</url-pattern>
		</servlet-mapping>
	</web-app>

3.Servlet的生命周期

(1)构造器:只被调用一次。第一次请求Servlet时创建Servlet的实例,调用构造器。Servlet是单例的
(2)init:只被调用一次。在创建好实例后立即被调用。
(3)service:每次请求都会调用,实际用于响应请求
(4)destory:只被调用一次。当前Servlet所在的web应用被卸载前调用,用于释放当前Servlet所占用的资源


4.load-on-startup参数

用以指定Servlet被创建的时机。若为负数,则在第一次请求时被创建。若为0或正数,则在当前web应用被Servlet容器加载时创建,且数组越小越早被创建。

	<servlet>
		<servlet-name>helloServlet</servlet-name>
		<servlet-class>com.ithings.servlet.HelloServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

5.<serlvet-mapping>通配符

可以用*匹配符配置<serlvet-mapping>,但是要注意,必须是*.do或者/开头的以/*结束的路径。/*.jsp不合法

对于如下的一些映射关系:

Servlet1 映射到 /abc/* 

Servlet2 映射到 /* 

Servlet3 映射到 /abc 

Servlet4 映射到 *.do 

问题:

当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应.        

【Servlet引擎将调用Servlet1。】

当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应.           

【Servlet引擎将调用Servlet3。】

当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应.  

【Servlet引擎将调用Servlet1。】

当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应.                            

【Servlet引擎将调用Servlet2。】

当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应.    

【Servlet引擎将调用Servlet2。】


6.ServletConfig

(1)getInitParameter(String name) 获取Servlet中配置的初始化参数

		<servlet>
			<servlet-name>helloServlet</servlet-name>
			<servlet-class>com.ithings.servlet.HelloServlet</servlet-class>
			<init-param>
				<param-name>username</param-name>
				<param-value>Tom</param-value>
			</init-param>
		</servlet>
		String username = servletConfig.getInitParameter("username");

(2)getInitParameterNames() 获取Servlet初始化参数的名称列表

		<servlet>
			<servlet-name>helloServlet</servlet-name>
			<servlet-class>com.ithings.servlet.HelloServlet</servlet-class>
			<init-param>
				<param-name>username</param-name>
				<param-value>Tom</param-value>
			</init-param>
			<init-param>
				<param-name>password</param-name>
				<param-value>123</param-value>
			</init-param>
		</servlet>
	
	Enumeration<String> names = servletConfig.getInitParameterNames();
	while(names.hasMoreElements()){
		String paramName = names.nextElement();
		System.out.println(paramName);
	}
(3)getServletContext() 返回ServletContext(当前web应用)

(4)getServletName() 返回servlet-name

7.ServletContext

(1)可由ServletConfig获取

servletCOnfig.getServletContext();

(2)代表当前web应用,可从中获取当前web应用的各个信息

1)getInitParameter(String name) getInitParameterNames() 获取当前web应用的初始化参数

<span style="white-space:pre">		</span><context-param>
			<param-name>driver</param-name>
			<param-value>com.mysql.jdbc.Driver</param-value>
		</context-param>
		
		ServletContext servletContext = servletConfig.getServletContext();
		String driverName = servletContext.getInitParameter("driver");
		Enumeration names = servletContext.getInitParameterNames();
		while(names.hasMoreElements()){
			String paramName = (String) names.nextElement();
			System.out.println(paramName);
		}

2)getRealPath(String path) 获取部署在服务器上的绝对路径,而不是部署前的路径

3)getContextPath() 获取当前web应用的名称

4)获取当前web应用的某一个文件对应的输入流

	InputStream in = servletContext.getResourceAsStream("db.properties");
		
	//使用classloader
	ClassLoader classLoader = getClass().getClassLoader();
        InputStream in = classLoader.getResourceAsStream("db.properties");
        System.out.println(in);


8.ServletRequest & ServletResponse

ServletRequest

(1)获取请求参数
	1)String getParameter(String name) 
	2)String[] getParameterValues(String name)
	3)Map getParameterMap()  
		Map<String,String[]> map = request.getParameterMap();
        for(Map.Entry<String,String[]> entry : map.entrySet()){
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
	4)Enumeration getParameterNames()  
		Enumeration names = request.getParameterNames();
        while(names.hasMoreElements()){
            String name = (String) names.nextElement();
        }

(2)获取请求的URI
	HttpServletRequest httpServletRequest = (HttpServletRequest)request;
	String requestURI = httpServletRequest.getRequestURI();
	System.out.println(requestURI); //  /HelloFilter/hello
	
(3)获取请求方式 GET/POST
	String method = httpServletRequest.getMethod();
	System.out.println(method);// POST
	
(4)针对GET请求,获取?后的字符串
	String queryString = httpServletRequest.getQueryString();
	System.out.println(queryString);// username=aa&password=123

(5)获取请求的servlet的路径
	String servletPath = httpServletRequest.getServletPath();
	System.out.println(servletPath);//  /hello

ServletResponse

(1)getWriter() 
	返回PrintWriter对象,调用该对象的print() 方法,把print()中的参数直接打印到客户的浏览器上
(2)setContentType()	
	设置相应的内容类型
	application/msword:word文档

9.GenericServlet

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable

(1)是Servlet接口和ServletConfig接口的实现类,但是一个抽象类,其中的service方法为抽象方法

(2)如果新建的Servlet程序直接继承GenericServlet会使开发更简洁

(3)具体实现:

1)在GenericServlet中声明了一个ServletConfig类型的成员变量,在init(ServletConfig)方法中对其进行了初始化

2)利用ServletConfig成员变量的方法实现了ServletConfig接口的方法

3)还定义了一个init()方法,在init(ServletConfig)方法中对其调用,子类可以直接覆盖init(),在其中实现对Servlet的初始化

4)不建议直接覆盖init(ServletConfig),因为如果忘记写super(ServletConfig),则会出现空指针异常

10.HttpServlet

(1)继承自GenericServlet

(2)在service方法中直接把ServletRequest和ServletResponse转为HttpServletRequest和HttpServletResponse,并调用重载了的service(HttpServletRequest, HttpServletResponse);

(3)实际应用中,直接继承HttpServlet即可


Filter


1.什么是Filter

(1)Filter可以对发送到Servlet的请求进行拦截,并对响应进行拦截

(2)Filter程序是一个实现了Filter接口的Java类,与Servlet程序相似,它由Servlet容器进行调用和执行(Servlet API中定义了三个接口类:Filter、FilterChain、FilterConfig)

(3)Filter程序需要在web.xml文件中进行注册和设置它要拦截的资源(JSP、Servlet、静态图片文件和静态html文件)

2.Filter的HelloWorld

(1)新建一个java类实现Filter
	public class FirstFilter implements Filter{
		@Override
		public void init(FilterConfig filterConfig) throws ServletException {
			System.out.println("init");
		}

		@Override
		public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
			System.out.println("do");
			chain.doFilter(request, response);			
		}

		@Override
		public void destroy() {
			System.out.println("destory");
		}
	}

(2)web.xml中注册和映射
	<?xml version="1.0" encoding="UTF-8"?>
	<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
		<filter>
			<filter-name>firstFilter</filter-name>
			<filter-class>com.ithings.FirstFilter</filter-class>
			<init-param>
				<param-name>param</param-name>
				<param-value>value</param-value>
			</init-param>
		</filter>
		<filter-mapping>
			<filter-name>firstFilter</filter-name>
			<url-pattern>/*.jsp</url-pattern>
		</filter-mapping>
	</web-app>

3.Filter的API

(1)public void init(FilterConfig filterConfig)

1)在创建Filter对象被加载时立即被调用,只调用一次。Filter实例是单例的。

2)FilterConfig相当于ServletConfig

3)可以在web.xml中配置当前Filter的初始化参数。配置方式也和Servlet类似。

		<filter>
			<filter-name>filterTest</filter-name>
			<filter-class>com.ithings.FilterTest</filter-class>
			<init-param>
				<param-name>param</param-name>
				<param-value>value</param-value>
			</init-param>
		</filter>

(2)public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

1)真正的Filter拦截的代码写在该方法中,每次拦截都会调用该方法

2)FilterChain:Filter链,多个Filter组成一个Filter链

doFilter(ServletRequest request, ServletResponse response) 

把请求传给Filter链的下一个Filter,若当前Filter是Filter链的最后一个Filter,把请求给目标Servlet或JSP

多个Filter拦截的顺序和web.xml文件中配置的filter-mapping的顺序有关

(3)public void destroy()

4 dispatcher元素:指定过滤器所拦截的资源被Servlet容器调用的方式

可以是REQUEST、 INCLUDE、 FORWARD、 ERROR之一,默认REQUEST。可以设置多个<dispatcher>子元素用来指定Filter对资源的多种调用方式进行拦截

    <filter-mapping>
        <filter-name>firstFilter</filter-name>
        <url-pattern>/hello.jsp</url-pattern>
        <dispatcher>REQUEST</dispatcher>		
    </filter-mapping>

(1)REQUEST:通过GET或POST请求直接访问

(2)FORWARD:通过RequestDispatcher的forward()方法访问

(3)INCLUDE:通过RequestDispatcher的include()方法访问

(4)ERROR:如果目标资源是通过声明式异常处理机制调用时,该过滤器被调用

	处理异常的几种方式:
		1)page指令:<%@ page errorPage="error.jsp" >
		2)web.xml中配置
			<error-page>
				<exception-type>java.lang.ArithmeticException</exception-type>
				<location>/error.jsp</location>
			</error-page>
		3)dispatcher
		<filter-mapping>
			<filter-name>firstFilter</filter-name>
			<url-pattern>/error.jsp</url-pattern>
			<dispatcher>ERROR</dispatcher>		
		</filter-mapping>

5 自定义HttpFilter 

	public abstract class HttpFilter implements Filter{
		private FilterConfig filterConfig;
		/*
		 * 不建议子类直接覆盖,会造成filterConfig初始化失败
		 */
		@Override
		public void init(FilterConfig filterConfig) throws ServletException {
			this.filterConfig = filterConfig;
		}
		/*
		 * 供子类继承的初始化方法
		 */
		protected void init(){}
		
		/*
		 * 直接返回init(FilterConfig filterConfig)的filterConfig对象
		 */
		public FilterConfig getFilterConfig() {
			return filterConfig;
		}
		
		/*
		 * 原生的doFilter方法,不建议子类直接覆盖
		 */
		@Override
		public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException{
			HttpServletRequest request = (HttpServletRequest)req;
			HttpServletResponse response = (HttpServletResponse)res;
			this.doFilter(request, response, chain);
		}
		
		/*
		 * 抽象方法,需要子类实现
		 */
		public abstract void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException;

		@Override
		public void destroy() {
		}
	}

6. Filter实例之禁用浏览器缓存

	public class NoCacheHttpFilter extends HttpFilter{
		@Override
		public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
			response.setDateHeader("Expires", -1);
			response.setHeader("Cache-Control", "no-cache");
			response.setHeader("Pragma", "no-cache");
			
			chain.doFilter(request, response);
		}
	}	

7. Filter实例之设置字符集

	public class EncodingFilter extends HttpFilter{
		@Override
		public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
			//从初始化参数中获取Encoding的值
			String encoding = getFilterConfig().getServletContext().getInitParameter("encoding");
			
			//设置字符集
			request.setCharacterEncoding(encoding);
			
			//放行
			chain.doFilter(request, response);
		}
	}

8.Filter实例之登陆验证

web.xml 

    <!--用户信息放入session中的名称-->
    <context-param>
        <param-name>userSessionKey</param-name>
        <param-value>USERSESSIONKEY</param-value>
    </context-param>
    
    <!--未登录,重定向的页面-->
    <context-param>
        <param-name>redirectPage</param-name>
        <param-value>/login/login.jsp</param-value>
    </context-param>
    
    <!--不需要拦截的URL列表-->
    <context-param>
        <param-name>uncheckedUrls</param-name>
        <param-value>/login/a.jsp,/login/list.jsp,/login/login.jsp,/login/doLogin.jsp</param-value>
    </context-param>
    
    <filter>
        <filter-name>loginFilter</filter-name>
        <filter-class>com.ithings.filter.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>loginFilter</filter-name>
        <url-pattern>/login/*</url-pattern>
    </filter-mapping>

LoginFilter.java

<span style="white-space:pre">	</span>public class LoginFilter extends HttpFilter{
		private String sessionKey = null;
		private String redirectPage = null;
		private String uncheckedUrls = null;
		
		@Override
		protected void init(){
			//从初始化参数中获取sessionKey,redirectPage,uncheckedUrls
			ServletContext servletContext = getFilterConfig().getServletContext();
			sessionKey = servletContext.getInitParameter("userSessionKey");
			redirectPage = servletContext.getInitParameter("redirectPage");
			uncheckedUrls = servletContext.getInitParameter("uncheckedUrls"); 
		}

		@Override
		public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
			//1.判断ServletPath是否为不需要检查的url,是则直接放行
			String servletPath = request.getServletPath();
			List<String> urls = Arrays.asList(uncheckedUrls.split(","));
			if(urls.contains(servletPath)){
				chain.doFilter(request, response);
				return;
			}
			
			//2.从session中获取sessionKey对应的值,若值不存在,则重定向到redirectPage,若存在,则放行
			Object user = request.getSession().getAttribute(sessionKey);
			if(user == null){
				response.sendRedirect(request.getContextPath() + redirectPage);
			}else{
				chain.doFilter(request, response);
			}
		}
	}

9.HttpServletRequestWrapper

(1)包装类
	public class MyHttpServletRequest extends HttpServletRequestWrapper{
		public MyHttpServletRequest(HttpServletRequest request) {
			super(request);
		}
		@Override
		public String getParameter(String name){
			String val = super.getParameter(name);
			if(val != null && val.contains(" fuck ")){
				val.replace(" fuck ", " **** ");
			}
			return val;
		}
	}
(2)使用
	HttpServletRequest req = new MyHttpServletRequest(request);
	chain.doFilter(req, response);

Listener

1.监听域对象自身的创建和销毁的事件监听器 ServletContextListener、HttpSessionListener、HttpServletRequest  

(1)ServletContextListener 创建类,实现ServletContextListener接口

	public class HelloServletContextListener implements ServletContextListener{
		@Override
		public void contextInitialized(ServletContextEvent sce) {
			System.out.println("ServletContextListener..init..");
		}

		@Override
		public void contextDestroyed(ServletContextEvent sce) {
			System.out.println("ServletContextListener..destory..");
		}
	}
(2)web.xml中注册   

    <listener>
        <listener-class>com.ithings.listener.HelloServletContextListener</listener-class>
    </listener>

(3)应用

1)创建数据库连接池

2)创建Spring的IOC容器

3)读取当前WEB应用的初始化参数

(4)API

    //ServletContext对象被创建即当前web应用被加载时,Servlet容器调用该方法
    public void contextInitialized(ServletContextEvent sce);
	
    //ServletContext对象被销毁即当前web应用被销毁时,Servlet容器调用该方法
    public void contextDestroyed(ServletContextEvent sce);

(5)ServletRequestListener、HttpSessionListener

	public class HelloServletContextListener implements ServletContextListener,ServletRequestListener,HttpSessionListener{
		@Override
		public void contextInitialized(ServletContextEvent sce) {
			System.out.println("ServletContext 被创建");
		}

		@Override
		public void contextDestroyed(ServletContextEvent sce) {
			System.out.println("ServletContext 被销毁");
		}

		@Override
		public void requestInitialized(ServletRequestEvent sre) {
			System.out.println("ServletRequest 被创建");
		}
		
		@Override
		public void requestDestroyed(ServletRequestEvent sre) {
			System.out.println("ServletRequest 被销毁");
		}

		@Override
		public void sessionCreated(HttpSessionEvent se) {
			System.out.println("HttpSession 被创建");
		}

		@Override
		public void sessionDestroyed(HttpSessionEvent se) {
			System.out.println("HttpSession 被销毁");
		}
	}

2.监听域对象中属性的增加和删除的事件监听器 ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener

public class HelloAttributeListener implements ServletContextAttributeListener, HttpSessionAttributeListener,ServletRequestAttributeListener{
  
	//添加属性时调用
    public void attributeAdded(ServletContextAttributeEvent event) {}
	//移除属性时调用
    public void attributeRemoved(ServletContextAttributeEvent event) {}
	//替换属性时调用
    public void attributeReplaced(ServletContextAttributeEvent event) {}
    public void attributeAdded(HttpSessionBindingEvent event) {}
    public void attributeRemoved(HttpSessionBindingEvent event) {}
    public void attributeReplaced(HttpSessionBindingEvent event) {}
	//可以获取到添加的属性名和属性值
    public void attributeAdded(ServletRequestAttributeEvent srae) {
        System.out.println("向request中添加了一个属性 " + srae.getName() +" : " + srae.getValue());
	}
    public void attributeRemoved(ServletRequestAttributeEvent srae){}
    public void attributeReplaced(ServletRequestAttributeEvent srae) {}
}

在web.xml中注册
    <listener>
        <listener-class>com.ithings.listener.HelloAttributeListener</listener-class>
    </listener>

3.监听绑定到HttpSession域中的某个对象的状态的事件监听器 HttpSessionBindingListener、HttpSessionActivationListener

(1)该监听器不需在web.xml中注册。注:该监听器很少被使用

(2)HttpSessionBindingListener

	public class Customer implements HttpSessionBindingListener{
		/*
		 * 当前对象被绑定到session时调用该方法
		 */
		@Override
		public void valueBound(HttpSessionBindingEvent event) {
			System.out.println("绑定到session");
			//提供的三个方法
			Object value = event.getValue();
			String sessionName = event.getName();
			HttpSession session = event.getSession();
		}
		/*
		 * 当前对象从session解除时调用该方法
		 */
		@Override
		public void valueUnbound(HttpSessionBindingEvent event) {
			System.out.println("从session移除");
		}
	}
	
	<%
		Customer customer = new Customer();
		session.setAttribute("customer",customer);
		System.out.println("---------------------");
		session.removeAttribute("customer");
	%>

(3)HttpSessionActivationListener

监听实现了该接口和Serializable的java类。session对象存储在tomcat服务器的work\Catalina\localhost\contextPath目录下

	public class HelloHttpSessionBindingListener implements HttpSessionActivationListener,Serializable{
		@Override
		public void sessionWillPassivate(HttpSessionEvent se) {
			System.out.println("向磁盘中写入session对象");
		}

		@Override
		public void sessionDidActivate(HttpSessionEvent se) {
			System.out.println("从磁盘中读取session对象");
		}
	}









评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值