Servlet基础之过滤器、监听器、文件上传下载
考虑到这些东西已经不被常用了,就把以前的笔记翻上来应付下好了,暂不炒冷饭。
Filter(过滤器)
过滤器的生命周期
在服务器启动的时候构造过滤器对象并且调用初始化方法。
在访问到映射路径时调用过滤器的过滤方法(doFilter)。
销毁的时候或者Reloading的时候调用过滤器的销毁方法.
登录过滤器
- 先强转request和response的对象类型
- 获取uri的路径
- 判断uri路径是否符合条件--符合条件则放行
- 不符合条件则判断session中是否有用户登录凭证--有则放行
- 没有则重定向
编码过滤器
- 把处理编码的代码抽取到过滤器中
- req.setCharacterEncoding("utf-8");
- 只针对post请求的编码处理
- 针对get的请求有2种
- 修改服务器的编码格式
- 编写包装类
- 多个过滤器的过滤顺序
- 过滤器的过滤顺序跟web.xml的配置有关。
- 放行后的代码则是服务器响应给客户端的时候执行,执行顺序与过滤顺序相反。
其他
过滤器是"链"在容器的处理过程中的。
这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。
这种访问使得过滤器可以检查并修改请求和响应的内容。
关于web.xml
Fiter的注册映射路径一般是/* 代表通配所有的路径。
用中间抽象类时要注意web.xml不能有该抽象类的注册,否则会默认实例该类,但抽象类不能实例化。
Listener(监听器)
监听器就是监听某个域对象的的状态变化的组件
监听器的相关概念
- 事件源:被监听的对象(三个域对象)
- request
- session
- servletContext
- 监听器:监听事件源对象事件源对象的状态的变化都会触发监听器(6+2)。
- 注册监听器:将监听器与事件源进行绑定。
- 响应行为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)。
监听器有哪些
- 第一维度按照被监听的对象划分:
- ServletRequest域
- HttpSession域
- ServletContext域
- 第二维度按照监听的内容分:
- 监听域对象的创建与销毁的
- 监听域对象的属性变化的
监听三大域对象的创建与销毁
监听三大域对象的监听器分别是:
- ServletContextListener
- HttpSessionListener
- ServletRequestListener
监听器的编写步骤(重点):
- 编写一个监听器类去实现监听器接口。
- 覆盖监听器的方法。
- 需要在web.xml中进行配置—注册。
监听ServletContext域的创建与销毁的监听器ServletContextListener
-
Servlet域的生命周期
- 何时创建:服务器启动创建
- 何时销毁:服务器关闭销毁
-
ServletContextListener监听器的主要作用
- 初始化的工作:初始化对象、初始化数据(加载数据库驱动、连接池的初始化)
- 加载一些初始化的配置文件(spring的配置文件)
- 任务调度(定时器—Timer/TimerTask)
监听Httpsession域的创建于销毁的监听器HttpSessionListener
- HttpSession对象的生命周期
- 何时创建:第一次调用request.getSession时创建
- 何时销毁:服务器关闭销毁、session过期(默认30分钟,修改默认的30分钟是在Tomcat的web.xml,修改当前项目的过期时间是在自己项目的web.xml中)、手动销毁。
- HttpSessionListener监听器的主要作用
- 由于每次访问网站都会默认创建session对象(jsp页面中page指令中的session属性默认为true,即被访问时创建session),可以用于计数网站访问过的人
监听ServletRequest域创建与销毁的监听器ServletRequestListener
- ServletRequest的生命周期
- 创建:每一次请求都会创建request
- 销毁:请求结束
- 用法同上
其他
剩余四分之三的知识点没写 (我也不知道几年前的我为什么没写,虽然现在我也不想写,后面写过Spring后再讲)
文件上传下载
其实都是旧代码了,没什么实际用处,辣鸡代码不看也罢
上传
- 修改项目设置
- 修改图片上传的目录位置
- 修改form表单属性
- 提交方式为:Post
- 添加属性为:enctype="multipart/form-data"
- 上传文件的type为:file
- 上传文件要设置name才能在后台获得
- 导包
- 对于文件上传,浏览器是以流的形式提交到服务器端的
- 如果直接用输入流解析请求参数会比较麻烦,一般采用apache提供的jar包组件:
- commons-fileupload-1.2.2.jar
- commons-io-2.2.jar
- Servlet
- 通过jar包实例化 磁盘工厂 对象
- 实例化一个 文件上传解析器,在构造方法中传递工厂对象
- 解决上传文件名的中文乱码问题
- 创建一个map/对象,用于存放表单数据
- 通过解析器解析前端发送的复合表单数据,返回一个集合
- 遍历这个集合,判断是否为非文本数据
- 使用工具包——存储在服务器路径下(注意解决重名问题)
- 提示用户修改名字
- 通过时间生成目录
- 通过UUID生成唯一文件名
- 处理表单信息
- 关流
假设有一个表单提交要上传图片
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
HashMap<String, String> map = new HashMap<>();
List<FileItem> list = upload.parseRequest(request);
for(FileItem item :list){
//判断是否为非文本数据
if (!item.isFormField()) {
...
}
}
//1.通过全局对象获取绝对路径
String path = getServletContext().getRealPath("Upload");
File file = new File(path);
//判断路径是否存在
if(!file.exists()){
file.mkdirs();
}
//绝对路径
UUID uuid = UUID.randomUUID();
File newfile = new File(filePath,uuid.toString()+"_"+fItem.getName());
is = fItem.getInputStream();
fos = new FileOutputStream(file);
//传递输入输出流拷贝文件
IOUtils.copy(is , fos);
stu.setImgUrl("Upload/"+uuid.toString()+"_"+fItem.getName());
//根据Key(input标签的name属性值)获取value值
String value = map.get(fItem.getFieldName());
if(value== null){
//代表第一次存储
map.put(fItem.getFieldName(),fItem.getString());
}else{
//不是第一次存储,复选框
map.put(fItem.getFieldName(),value+","+fItem.getString());
}
//把map中的数据存放到stu对象中,这里用到BeanUtils的jar包
BeanUtils.populate(stu,map);
//注意后面关流
....
下载
- 前端页面
- 下载链接传递到Servlet,并带上path=图片相对路径的属性
- Servlet
// 获取前端传递的path属性
String path = request.getParameter("path");
// 截取出文件名
String fileName = path.substring(path.lastIndexOf("/")+1);
// 解决文件名的中文乱码问题
fileName = URLEncoder.encode(fileName,"utf-8");
// 获取图片完整路径
path = getServletContext().getRealPath(path);
// 设置响应头
response.setHeader("Content-disposition","attachment;fileName="+fileName);
// 创建输入输出流,用工具类复制
fis = new FileInputStream(path);
os = response.getOutputStream();
IOUtils.copy(fis,os);
// 关流
....