监听器
一、Listener 监听器
1. 概述
- Servlet技术中三大组件之一 - Servlet Filter Listener
- Servlet技术规范中sun预先定义了八大监听器用来监听web开发中对应的事件
- 监听器可以用来监听web应用执行过程中相关的事件 来进行对应的处理
2. 开发监听器步骤
- 写一个类实现指定监听器接口
- 在web.xml文件中配置监听器
3. 监听三大作用域创建和销毁的监听器
-
ServletContextListener:该监听器负责监听ServletContext的创建和销毁
生命周期:在web应用启动时创建出来之后一直驻留在内存中唯一的代表当前web应用直到web应用移除出容易或服务器关闭时随着web应用的销毁ServletContext对象跟着被销毁 作用范围:整个web应用范围 主要功能:在整个web应用范围内 整个web应用存活期间 共享数据
-
HttpSessionListener:负责监听HttpSession对象的创建和销毁事件
生命周期:在第一次调用request.getSession()时创建 自杀 - session.invalidate 超时 - 30分钟 意外身亡 - 服务器非正常关闭 作用范围:整个会话 主要功能:在整个会话范围内 整个会话的生命周期期间 共享数据 钝化:在服务器正常关闭时 仍然在存活期间的session 会被序列化后保存在tomcat的work目录下 这个过程称之为session的钝化 活化:在服务器正常启动时 会将钝化的session再恢复到内存中 继续使用 这个过程称之为session的活化
-
ServletRequestListener
生命周期:请求开始时创建 请求结束时销毁 作用范围:整个请求 主要功能:在请求过程中 在请求范围内 共享数据
4.监听三大作用域中属性增加、修改或减少的监听器
- ServletContextAttributeListener
- HttpSessionAttributeListener
- ServletRequestAttributeListener
5. 使javabean自己感知 自己在session域中状态变化的监听器
- HttpSessionBindingListener - 使javabean自己感知自己在session域中 被加入 或 移除的 状态变化的监听器
- HttpSessionActivationListener - 使javabean自己感知自己在session域中 随着session被钝化 活化 状态变化的监听器
- 这两个监听器比较特殊 不需要单独写类来实现 也不需要在web.xml中进行配置 只需要让javabean自己来实现即可
6.EasyMall中监听器的应用
- 开发EasyMallServletContextListener
- 在ServletContext创建时 向 ServletContext域中增加 app 属性 值为应用的路径 在ServletContext销毁时删除该属性 这样 以后需要在jsp页面中写应用路径时 直接写$(app)即可
二、文件上传
1.文件上传概述
- 在web开发中经常需要从客户端向服务器上传文件,如:上传照片、上传新闻图片、上传附件等等。这些都需要通过WEB开发中的文件上传技术实现。
2. 文件上传步骤
- 提供一个带有文件上传项的表单
- 文件上传的输入框必须有name属性才能被上传
- 文件上传的表单必须是post提交
- 文件上传的表单必须设置enctype=multipart/form-data
在Servlet中处理文件上传相关的逻辑
方式1:
可以通过javaee原生的api request.getInputStream 来获取请求中实体内容的流
获取到流中的数据后 解析 处理 – 非常麻烦
方案2:
使用开源工具实现
Apache提供的文件上传包 - Commons-fileupload
3.Commons-fileupload
- 下载并导入对应的包
- Commons-fileupload
- commons-io
(1)文件上传工厂 DiskFileItemFactory
public DiskFileItemFactory(int sizeThreshold, java.io.File repository)
// sizeThreshold - 指定内存缓冲区的大小
//repository - 指定临时文件存放的位置
/*文件上传 时需要将请求的实体内容 全部读取后 才能做处理
此时需要将实体内容缓冲起来 内存缓冲快 但是耗费内存 文件缓冲慢 但是可以存放大量数据
所以此处提供了两个选项 如果数据大小小于sizeThreshold则使用内存做缓冲 速度快 如果文件大小超过了该限制则在repository指定的位置下创建临时文件来缓冲数据*/
(2)上传文件核心类 ServletFileUpload
ServletFileUpload fileUpload = new ServletFileUpload(factory);
//判断当前提交数据表单是否是一个enctype为multipart/form-data类型的表单
boolean isMultipartContent(HttpServletRequest request)
//指定处理文件名时使用的编码集
setHeaderEncoding(java.lang.String encoding)
//控制单个文件大小最大值
setFileSizeMax(long fileSizeMax)
//控制总的文件大小最大值
setSizeMax(long sizeMax)
//解析request对象 获取 FileItem的集合
List<FileItem> parseRequest(HttpServletRequest request)
//设置上传文件监听器
setProgressListener(ProgressListener pListener)
(3)文件上传项 FileItem
List<FileItem> parseRequest(HttpServletRequest request)
//判断当前FileItem是不是一个普通字段项 如果返回true表示这是一个普通字段项 返回false表示是一个文件上传项
boolean isFormField()
//如果是普通字段项
String getFieldName() //获取字段项的名称
String getString() //获取字段项的值
String getString(String encode) //获取字段项的值
//如果是文件上传项
String getName() //获取文件名
InputStream getInputStream() //获取文件内容的流
delete() //删除临时文件
(4)ie上传文件 文件名 Bug 处理
if(fname.contains("\\")){
fname = fname.substring(fname.lastIndexOf("\\"));
}
(5)文件上传保存位置问题
文件上传保存的位置一定不能被外界直接访问 防止 用户用户浏览器访问 下载资源 或执行jsp恶意代码
要么保存在WEB-INF下保护起来 要么放在本地磁盘 其他位置 保证通过浏览器无法直接访问
(6)上传文件重名问题
多个上传名称相同时 文件会发生覆盖
应该想办法让文件名 尽量不要重复 - 在文件名的前面拼接UUID来保证文件名绝对不会重复
(7)上传文件目录下文件过多 - hash分目录存储
一个文件夹下文件过多 会造成 访问缓慢 甚至有可能无法访问
所以 应该想办法 将这些文件分目录存储
计算文件名的hash - 散列
将hash值转换为16进制的字符串 - 共8位 值0-9 a-f
将这个hash字符串截取出每一位作为一级目录
最终将上文件放置到8级hash目录下 共有 16^8 个可能的文件夹 分目录存放文件 从而保证一个文件夹文件不会过多
(8)文件上传进度监听
upload.jsp页面中 为表单提交事件增加函数触发 增加定时器 每隔一段时间 通过ajax发送是那个请求 访问服务器 获取最新的文件上传进度 展示到页面
$(document).ready(function(){
$("#f").submit(function(){
window.setInterval(function(){
$.get("${pageContext.request.contextPath }/servlet/UploadProgressServlet", function(data){
$("#in_div").width(data);
});
}, 10);
})
});
-
UploadServlet中 为问件上传注册监听器 计算各种指标 并且将计算的指标 存入session
-
UploadProgressServlet中 从session中获取上传进度信息 作为响应发回给ajax访问