JavaWeb详解(第三篇)之Servlet基础简介-过滤器、监听器

    JavaWeb的三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。前面我们学习了Servlet ,接下来我们在了解一下Filter 过滤器和Listener 监听器。

1、Filter 过滤器

1.1、什么是Filter 过滤器

    Filter 过滤器它是 JavaEE 的规范。也就是接口。可以对指定URL请求进行拦截,拦截之后在过滤器中进行相应的处理/判断。

    Filter 过滤器它的作用是:拦截请求,过滤响应。

    拦截请求常见的应用场景有: 1)权限检查;2)日记操作 ;3)事务管理...等等。

1.2、Filter 入门

    案例描述:在首页,访问个人信息页面,如果没有登陆则不允许访问。

1)编写一个类去实现Filter 接口

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class FilterDemo implements Filter{

	/**
	 * 用于拦截请求
	 */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub
		HttpServletRequest httpServletRequest = (HttpServletRequest) request; 
		HttpSession session = httpServletRequest.getSession(); 
		Object user = session.getAttribute("user"); 
		// 如果等于 null,说明还没有登录:则不允许访问私人页面
		if (user == null) { 
			request.getRequestDispatcher("/login.jsp").forward(request, response);
			return;
		} else { 
			// 让程序继续往下访问用户的目标资源:如果没有其他的过滤器,将访问请求的资源;如果有过滤器则继续进入其他过滤器
			chain.doFilter(request,response);
		}
	}
}

2)编写一个InfoServlet

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InfoServlet extends HttpServlet{

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		  response.setContentType("text/html;charset=gbk");
	      PrintWriter out = response.getWriter();
	      out.println("私人空间,请谨慎查看!");
	}
}

3)修改index.jsp主页

<body>
    <div>我是页头</div>
        <a href="/persion/infoServlet">查看我的信息</a>
    <div>我是页尾</div>
  </body>

4)配置web.xml

<!--filter 标签用于配置一个 Filter 过滤器--> 
<filter> 
    <filter-name>FilterDemo</filter-name> 
    <filter-class>com.cn.filterAndListener.FilterDemo</filter-class> 
</filter>
<filter-mapping>
    <filter-name>FilterDemo</filter-name>
    <!-- 匹配规则同servlet,支持/*也支持*.do 
        .../persion/infoServlet 访问此链接会被拦截
    -->
    <url-pattern>/persion/infoServlet</url-pattern>
</filter-mapping>

案例效果:

java 过滤数组取某个元素连接_监听器

     成功拦截了,但是我们发现有一个问题。我之前的登陆页面转发过去,怎么验证码不显示了呢?一查,发现路径好像不对:

扩展:补充说明base标签的作用

public class FilterDemo implements Filter{

	/**
	 * 用于拦截请求
	 */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub
		HttpServletRequest httpServletRequest = (HttpServletRequest) request; 
		HttpSession session = httpServletRequest.getSession(); 
		Object user = session.getAttribute("user"); 
		// 如果等于 null,说明还没有登录:则不允许访问私人页面
		if (user == null) {
			//注:"/" 跟目录 request.getRequestDispatcher("/"),表示当前工程http://localhost:8080/
			//当我使用/login.jsp,确实可以转发到登陆页面,但是此时的登陆页面的url:http://localhost:8080/persion/infoServlet
			request.getRequestDispatcher("/login.jsp").forward(request, response);
			return;
		} else { 
			// 让程序继续往下访问用户的目标资源:如果没有其他的过滤器,将访问请求的资源;如果有过滤器则继续进入其他过滤器
			chain.doFilter(request,response);
		}
	}
}
<!--把src目录复制下来-->
<img id="codeimg" style="width: 60px;height:20px;" src="ImageServlet?0.14947579772812647">
跳转的链接是:
http://localhost:8080/persion/ImageServlet?0.14947579772812647
我们没有在login.jsp中声明<base>这里的base路径默认是http://localhost:8080/persion/

<!--base 标签设置页面相对路径工作时参照地址的地址 href 属性就是参数的地址值 -->
所以我们得到的是上诉地址,导致验证码无法显示
把js中的代码改成如下:发现正常了,但是这样做并不好,业务我们根本不知道从第几层,这种做法不通用
window.document.getElementById("codeimg").src="../"+url+"?"+Math.random();

我们在login.jsp页面中加入base设置页面相对路径工作时参照地址
<base href="/">

最终我们看到:

java 过滤数组取某个元素连接_java_02

1.3、Filter 应用

1.3.1、过滤器解决中文乱码问题

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
   //全拦截先设置一波字符编码
   request.setCharacterEncoding("UTF-8");
   chain.doFilter(request, response);
}

2、Listener 监听器

2.1、什么是监听器

    如果你属性JAVA的GUI图形界面,应该接触过很多监听器。比如:监听键盘事件、按钮的点击事件,然后触发某种动作。这就是监听器的作用:无需主动调用,自动触发。

    监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。

在Servlet规范中定义了多种类型的监听器:

1)监听对象的创建和销毁

    a)ServletRequestListener:可以在请求时获得通知

    b)HttpSessionListener:可以用来收集在线者信息,或者更改会话列表时获得通知

    c)ServletContextListener:可以获取web.xml里面的参数配置

2)监听对象属性变化

    a)ServletContextAttributeListener

    b)HttpSessionAttributeListener

    c)ServletRequestAttributeListener

3)监听Session对象

    a)HttpSessionBindingListener

    b)HttpSessionActivationListener

2.2、监听器入门

1)新建一个ListenerDemo

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class ListenerDemo implements  HttpSessionListener,HttpSessionAttributeListener{

	 // 新建一个session时触发此操作  
    public void sessionCreated(HttpSessionEvent se) {  
        System.out.println("新建一个session");
    }  
    
    // 添加session时触发此操作
	public void attributeAdded(HttpSessionBindingEvent e) {
	       HttpSession session = e.getSession();
	       String name = (String) session.getAttribute(session.getAttributeNames().nextElement());
	       System.out.println("我可以把session添加到对象中,值为:"+name);
	}
	
    public void attributeRemoved(HttpSessionBindingEvent e) {
       System.out.println("我可以把session从对象中移除");
    }
    
    public void attributeReplaced(HttpSessionBindingEvent e) {  
        System.out.println("替换");
    }
}

2)修改xml

<listener>
    <!-- <display-name>ListenerDemo</display-name> -->
    <listener-class>com.cn.filterAndListener.ListenerDemo</listener-class>
</listener>

3)使用我们之前的案例:SessionDemo

案例效果:

java 过滤数组取某个元素连接_java 过滤数组取某个元素连接_03

注:三者的执行顺序:listener->Filter->servlet。简单记为:理(Listener)发(Filter)师(servlet)

3、其他知识补充

3.1、错误页面

1)新建ExceptionServletDemo

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ExceptionServletDemo extends HttpServlet {

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

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int i = 9/0;
		System.out.println("大兄弟,代码出错了啊!!!");
	}
}

2)web.xml

<servlet>
    <servlet-name>ExceptionServletDemo</servlet-name>
    <servlet-class>com.cn.filterAndListener.ExceptionServletDemo</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ExceptionServletDemo</servlet-name>
    <url-pattern>/ExceptionServletDemo</url-pattern>
</servlet-mapping>

<!--配置捕错误时进入的页面-->
<error-page>
    <exception-type>java.lang.ArithmeticException</exception-type>
    <location>/error.jsp</location>
</error-page>
<!--也可以配置-->
<error-page>
     <error-code>404</error-code>
     <location>/error.jsp</location>
</error-page>

案例效果:

java 过滤数组取某个元素连接_监听器_04

3.2、上传下载

3.2.1、上传

     需要:(SmartUpload.jar)包

import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jspsmart.upload.File;
import com.jspsmart.upload.Files;
import com.jspsmart.upload.Request;
import com.jspsmart.upload.SmartUpload;
import com.jspsmart.upload.SmartUploadException;

public class UploadServlet extends HttpServlet {

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

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			String dirPath = this.getServletContext().getRealPath("/images");
			// 接收客户端上传的文件
			// 创建 SmartUpload 对象用于接收文件的上传
			SmartUpload su = new SmartUpload();
			// 通过 su 对象初始化 request 中的数据
			su.initialize(this.getServletConfig(), request, response);
			// 设置上床文件的限制信息
			su.setAllowedFilesList("jpg,png,bmp,gif");
			// 设置单个上传文件为2M
			su.setMaxFileSize(2 * 1024 * 1024);
			// 执行上传:上传之后,页面提交的数据都在 su 对象中
			su.upload();
			// 从 su 对象中获取数据(文件和字段)
			// 获取到 su 中上传的文件
			Files files = su.getFiles();
			// 获取到包含所有文本字段的 request 对象
			Request r = su.getRequest();
			// 遍历files获取到所有上传的文件(允许批量上传)
			for (int i = 0; i < files.getCount(); i++) {
				File file = files.getFile(i);
				file.saveAs(dirPath + "/" + file.getFileName());
			}
			// 从 r 中获取到需要的字段
			String name = r.getParameter("userName");
			String pass = r.getParameter("userPass");
			String[] fns = new java.io.File(dirPath).list();
			ArrayList<String> fileNames = new ArrayList<String>();
			for (String f : fns) {
				fileNames.add(f);
			}
			request.setAttribute("fileNames", fileNames);
			request.getRequestDispatcher("list.jsp").forward(request, response);
		} catch (SmartUploadException e) {
			e.printStackTrace();
		}
	}
}

3.2.2、下载

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DownloadServlet extends HttpServlet {
   public void doGet(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {
      this.doPost(request, response);
   }

   public void doPost(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {
      // 接受客户端需要下载的文件名
      String fileName = request.getParameter("fname");
      // 获取到文件存放的目录
      String dirPath = this.getServletContext().getRealPath("/images");
      // 要下载的文件是
      File f = new File(dirPath + "/" + fileName);
      // 再将图片信息发送给客户端之前,设置响应信息的格式
      // 设置相应数据的格式为浏览器无法解析的格式
      response.setContentType("application/pdf");
      // 设置文件的头信息
      response.setHeader("Content-Disposition", "attachment;filename="
            + fileName);
      // 设置响应数据的大小
      response.setContentLength((int) f.length());
      // 开始下载
      FileInputStream fis = new FileInputStream(f);
      OutputStream out = response.getOutputStream();
      byte[] buff = new byte[102400];
      int len = -1;
      while ((len = fis.read(buff)) != -1) {
         out.write(buff, 0, len);
         out.flush();
      }
      out.close();
   }
}