大数据正式22
监听器
- 概述
- Listener--监听器
- Servlet技术中的三大组件之一【Servlet、Filter、Listener】
- 简单、应用少
- 监听器可以用来监听web应用执行过程中的相关的事件,来进行对应的处理
- 应用
- 写一个类实现监听器接口
- web中配置
-
监听三大作用域创建和监听器
-
ServletContextListener
- 生命周期:web部署到下线
- 作用范围:整个web应用
- 主要功能:整个web应用中共享数据
-
例子
package com.peng.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyServletContextListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent arg0) { System.out.println("context Destory"); } public void contextInitialized(ServletContextEvent arg0) { System.out.println("context Init"); } }
<!-- 监听器的配置 --> <listener> <listener-class>com.peng.listener.MyServletContextListener</listener-class> </listener>
-
HttpSessionListener
- 生命周期:第一次调用request.getSession()
- 作用范围:整个web应用的额会话周期
-
主要功能:整个会话的生命周期共享数据
package com.peng.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MySessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent arg0) { System.out.println("session create!!!"); } public void sessionDestroyed(HttpSessionEvent arg0) { System.out.println("session destory!!!"); } }
<!-- 监听器的配置 --> <listener> <listener-class>com.peng.listener.MySessionListener</listener-class> </listener>
-
ServletRequestListener
- 生命周期:一次请求和一次响应的过程中
- 作用范围:一次请求和一次响应的过程中
-
主要功能:一次请求和一次响应的过程中共享数据
package com.peng.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; public class MyRequestListener implements ServletRequestListener { public void requestDestroyed(ServletRequestEvent arg0) { System.out.println("destory ServletRequestListener"); } public void requestInitialized(ServletRequestEvent arg0) { System.out.println("init ServletRequestListener"); } }
<!-- 监听器的配置 --> <listener> <listener-class>com.peng.listener.MyRequestListener</listener-class> </listener>
-
ServletContextAttributeListener
package com.peng.listener; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; public class MyServletContextListener implements ServletContextAttributeListener { public void attributeAdded(ServletContextAttributeEvent arg0) { } public void attributeRemoved(ServletContextAttributeEvent arg0) { } public void attributeReplaced(ServletContextAttributeEvent arg0) { // getValue为旧值 // 获取新值 arg0.getServletContext().getAttribute(arg0.getName()); } }
-
HttpSessionAttributeListener
package com.peng.listener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MySessionAttributeListener implements HttpSessionAttributeListener { public void attributeAdded(HttpSessionBindingEvent arg0) { } public void attributeRemoved(HttpSessionBindingEvent arg0) { } public void attributeReplaced(HttpSessionBindingEvent arg0) { // TODO Auto-generated method stub } }
-
ServletRequestAttributeListener
package com.peng.listener; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; public class MyRequestSAttributeListener implements ServletRequestAttributeListener { public void attributeAdded(ServletRequestAttributeEvent arg0) { } public void attributeRemoved(ServletRequestAttributeEvent arg0) { } public void attributeReplaced(ServletRequestAttributeEvent arg0) { // TODO Auto-generated method stub } }
-
使javabean自己感知在session域中的变化HttpSessionBindingListener(加入,移除)
-
注:javabean实现这个接口,重写方法;web.xml中无须配置
package compeng.javabean; import java.io.Serializable; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; public class PersonBinding implements Serializable, HttpSessionBindingListener { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void valueBound(HttpSessionBindingEvent arg0) { // 加入 } public void valueUnbound(HttpSessionBindingEvent arg0) { // 移出 } }
-
-
使javabean自己感知在session域中的变化HttpSessionActivationListener(钝化,活化)
- 注:javabean实现这个接口,重写方法;web.xml中无须配置
- 注:javabean记得实现序列化接口
-
活化回来时,对象不是同一个,只是携带的信息一样而已
package compeng.javabean; import java.io.Serializable; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionEvent; class PersonBinding implements Serializable, HttpSessionActivationListener { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void sessionDidActivate(HttpSessionEvent arg0) { // 序列化 } public void sessionWillPassivate(HttpSessionEvent arg0) { // 反序列化 } }
-
钝化和活化
- 钝化
- 在服务器正常关闭时,仍然存活的session会被钝化到work目录下
- 活化
- 在服务器正常开启时,将work目录下session.ser文件重写加载到服务器
EasyMall监听器的使用
- EasyMall应用开启时设置项目路径到“app”变量中
- EasyMall应用关闭时销毁“app”变量
-
例子
package com.easymall.listener; import javax.servlet.ServletContextEvent; public class ServletContextListener implements javax.servlet.ServletContextListener { public void contextDestroyed(ServletContextEvent arg0) { // 将项目路径移除 arg0.getServletContext().removeAttribute("app"); } public void contextInitialized(ServletContextEvent arg0) { // 将项目的路径存到app这个变量中 arg0.getServletContext().setAttribute("app", arg0.getServletContext().getContextPath()); } }
文件上传
- 步骤
- 带有文件上传的表单
- 必须有name
- 必须为post方式
- enctype的参数配置:multipart/form-data
- 在servlet写相应的逻辑【麻烦的逻辑】
- 获取流
- 变成字符串
- 切分字符串根据头信息
- 获取想要的文件
- enctype的参数配置:multipart/form-data
- 在servlet写相应的逻辑【简单的方式】
- Commaons-fileupload.jar包;commans-io.jar包
- 过程
- 创建文件上传工厂DiskFileItemFactory【内存缓冲区大小;文件临时存放目录】【文件全部传入才能做处理:放内存中--速度快但是占资源;放文件--速度慢,但是文件大小可以基本不受限制】【超过内存缓冲区,就执行文件临时存放目录】
- 创建文件上传的核心类ServletFileUpload
- isMultipartCotent(HttpServletRequest req)//判断当前上传的表单是否是multipart/form-data
- List parseRequest(HttpServletRequest req)//将请求头解析成文件的列表
- setFileSizeMax(long size)//控制文件上传的大小(Byte)
- setSizeMax(long size)//控制总的文件上传的最大值
- FileItem:文件上传项目--遍历item分别做处理
- isFormFiled判断当前FileItem是不是一个普通字段项----返回false为文件上传项
- 普通字段项
- getFieldName//获取字段项的名称
- getString//字段项的值
- 文件上传项
- getName//获取文件的名称
- getInputStream//获取文件的输入流
- 普通字段项
- isFormFiled判断当前FileItem是不是一个普通字段项----返回false为文件上传项
- 如果是文件,将获取到FileItem的输入流写入到文件的输出流中
- 遇到的问题
- 文件名乱码(文件名称是中文名时)
- 上传文件核心类的设置编码:setHeaderEncoding(encode)
- 文件内容的乱码
- response.setHeaderEncoding("utf-8")解决不了乱码
- FileItem.getString(encode)
- 临时文件未删除
- FileItem.delete(记得该关的流关掉,要不删不了文件)
- IE浏览器上传
- Item.getName获取到的文件是全路径名(例如:C://a/b/c.txt)
- 问题解决--只获取文件名
- 文件上传保存的位置问题
- 为了安全--文件保存的位置一定不能让外界直接访问
- Web-Inf下
- 本地文件的位置外界无法访问到
- 为了安全--文件保存的位置一定不能让外界直接访问
- 文件重复--同名文件的覆盖
- 尽量让文件名不要重复UUID(参考:时间+CPU时钟+。。。)
- UUID.randomUUID().toString
- 上传目录下文件过多:访问缓慢、甚至无法访问
- 分目录存放
- Integer.toHexString(int)+ 不够八位补0【HashCode不一定是唯一的】
- 哈希特点:散列(相同二进制得到的数据相同)
- 例:a/1/b/3/1/1/4/b/1bacbaaa.png
- 总共产生的文件夹168
- 文件名乱码(文件名称是中文名时)
- 文件上传进度
- ServletFileUpload.setProgressListener(ProgressListener pro);
- 带有文件上传的表单
简单例子
- index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> </head> <body bgcolor="#00ff00" text="#ffffff">${requestScope.message} </body> </html>
- fileUp.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>文件上传</title> </head> <body bgcolor="#ff00ff" text="#00ffff"> <center> <h1>name:</h1> <input type="text" name="name" /> <h1>请选择文件:</h1> <form action="FileUpServlet" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" value="上传文件" /> </form> </center> </body> </html>
-
FileUpServlet
package com.peng.ser; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class FileUpServlet 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 { // 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全 String savePath = this.getServletContext().getRealPath( "/WEB-INF/upload"); File file = new File(savePath); // 判断上传文件的保存目录是否存在 if (!file.exists() && !file.isDirectory()) { System.out.println(savePath + "目录不存在,需要创建"); // 创建目录 file.mkdir(); } // 消息提示 String message = ""; try { // 使用Apache文件上传组件处理文件上传步骤: // 1、创建一个DiskFileItemFactory工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 2、创建一个文件上传解析器 ServletFileUpload upload = new ServletFileUpload(factory); // 解决上传文件名的中文乱码 upload.setHeaderEncoding("UTF-8"); // 设置文件的大小 upload.setFileSizeMax(2 * 1024 * 102);// 设置单个文件的最大值 upload.setSizeMax(50 * 1024 * 1024);// 设置总的文件的总的大小 // 3、判断提交上来的数据是否是上传表单的数据 if (!ServletFileUpload.isMultipartContent(request)) { // 按照传统方式获取数据 return; } // 4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项 List<FileItem> list = upload.parseRequest(request); for (FileItem item : list) { // 如果fileitem中封装的是普通输入项的数据 if (item.isFormField()) { String name = item.getFieldName(); // 解决普通输入项的数据的中文乱码问题 String value = item.getString("UTF-8"); // value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); } else {// 如果fileitem中封装的是上传文件 // 得到上传的文件名称, String filename = item.getName(); System.out.println(filename); if (filename == null || filename.trim().equals("")) { continue; } // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: // c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt // 处理获取到的上传文件的文件名的路径部分,只保留文件名部分 filename = filename .substring(filename.lastIndexOf("\\") + 1); // 获取文件名的UUID String uuid_fileName = UUID.randomUUID().toString() + "_" + filename; // 哈希目录--利用文件的名称生成8层文件夹 String hashCod_8 = Integer.toHexString(uuid_fileName .hashCode()); while (hashCod_8.length() < 8) { hashCod_8 = "0" + hashCod_8; } for (int i = 0; i < hashCod_8.length(); i++) { savePath += "\\" + hashCod_8.charAt(i); } File dir = new File(savePath); dir.mkdirs(); // 获取item中的上传文件的输入流 InputStream in = item.getInputStream(); // 创建一个文件输出流 FileOutputStream out = new FileOutputStream(savePath + "\\" + uuid_fileName); // 创建一个缓冲区 byte buffer[] = new byte[1024]; // 判断输入流中的数据是否已经读完的标识 int len = 0; // 循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 while ((len = in.read(buffer)) != -1) { // 使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" // + filename)当中 out.write(buffer, 0, len); } // 关闭输入流 in.close(); // 关闭输出流 out.close(); // 删除处理文件上传时生成的临时文件 item.delete(); message = "文件上传成功!"; } } } catch (Exception e) { message = "文件上传失败!"; e.printStackTrace(); } request.setAttribute("message", message); request.getRequestDispatcher("/index.jsp").forward(request, response); } }
加入进度显示的文件上传
- 原生js+原生ajax
- http://www.jb51.net/article/70521.htm
- 超级棒的一篇文章
- http://m.blog.csdn.net/liuzuochen/article/details/1516522