文件上传与下载、监听器、过滤器
A.文件上传
1.概述
将客户端的文件,保存到服务端
2.对表单的限制
表单属性enctypr必须为:multipart/form-data
ecctypr:指表单发送数据的编码方式
appliaction/x-www-form-urlencoded:数据进行URL编码
text/plain:纯文本发送
multipart/form-data:可以发送二进制数据,专门用于文件上传
提交的方式必须为post
3.前端网页
<body> <form action="${ pageContext.request.contextPath }/upload" method="post" enctype="multipart/form-data"> <input type="file" name="myfile" /> <input type="submit" value="上传" /> </form> </body>
4.后台
使用commons-fileupload组建解析消息
在WebRoot下创建文件夹接收文件,并导入jar包
对Servlet限制
a.request.getParameter()不能使用,即使用了也获取的是null
b.使用request.getInputStream()来获取所有消息体数据,然后解析
5.步骤代码
package org.xxxx.demo; import java.io.File; import java.io.IOException; 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.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class UpLoadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { // 设置编码 request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); // 创建工厂对象 DiskFileItemFactory factory = new DiskFileItemFactory(); // 创建文件上传对象 ServletFileUpload upload = new ServletFileUpload(factory); // 获取表单对象 List<FileItem> files = upload.parseRequest(request); // 遍历表单对象 for (FileItem f : files) { // 半段文本框类型 if (f.isFormField()) { // 普通文本框,获取键和值 String name = f.getName(); String value = f.getString("utf-8"); System.out.println(name + "---" + value); } else { // 是文件文本框 // 获取文本框名 String fieldName = f.getFieldName(); // 获取文件名 String fileName = f.getName(); // 让文件名随机变化,防止上传相同的文件被覆盖 fieldName = UUID.randomUUID().toString().replaceAll("-", "") + fieldName; // 获取文件大小 long size = f.getSize(); // 获取文件类型 String type = f.getContentType(); System.out.println(fieldName + "=" + fileName + "=" + size + "=" + type); // 把文件上传到服务器端 // 获取真实路径 String realPath = this.getServletContext().getRealPath("/UpLoad"); // 封装 File file = new File(realPath, fileName); // 写入文件 f.write(file); } } } catch (FileUploadException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
6.结果
启动服务器
选择文件上传
查看服务器路径webapps/工程名/UpLoad
B.文件的下载
1.概述
服务器端保存到客户端
请求下载是GET请求
注意:注意中文乱码的问题
每个浏览器的编码格式不同
所以要针对不同浏览器进行解码
尽量用英文
中文部分浏览器解决方式(在这就不掩饰)
// 获取浏览器的版本信息,根据不同的浏览器,发送不同的数据(文件名称) String agent = request.getHeader("user-agent"); if (agent.contains("MSIE")) { // IE浏览器 filename = URLEncoder.encode(filename, "utf-8"); filename = filename.replace("+", " "); } else if (agent.contains("Firefox")) { // 火狐浏览器 BASE64Encoder base64Encoder = new BASE64Encoder(); filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?="; } else if (agent.contains("Chrome")) { // google浏览器 filename = URLEncoder.encode(filename, "utf-8"); } else { // 其它浏览器 filename = URLEncoder.encode(filename, "utf-8"); }
2.创建文件
3.前台网页
<body> <a href="${ pageContext.request.contextPath }/down?filename=abc.txt">点击下载</a> </body>
4.后台
package org.xxxx.demo; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; public class DownLoadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取文件名 String filename = request.getParameter("filename"); // 获取绝对路径 String realPath = this.getServletContext().getRealPath("/download"); // 封装文件 File file = new File(realPath, filename); // 告诉浏览器弹框,让用户选择保存 response.setHeader("content-disposition", "attachment;filename=" + filename); // 告诉浏览器文件类型 response.setHeader("content-type", this.getServletContext().getMimeType(filename)); // 获取流 FileInputStream in = new FileInputStream(file); ServletOutputStream out = response.getOutputStream(); IOUtils.copy(in, out); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
5.结果
运行服务器
下载
C.监听器
1.作用
监听web中的三个域对象
a.监听三个对象的创建和销毁
ServletContextListener
ServletRequestListener
HttpSessionListener
b.监听三个对象属性的变化
ServletContextAttributeListener
ServletRequestAttributeListener
HttpSessionAttributeListener
c.监听session中javabean的状态
HttpSessionActivationListener(钝化和活化)
HttpSessionBindingListener(绑定和解绑)
2.创建和销毁(以request为例)(其他两个类似)
创建:请求
销毁:响应生成
a.创建一个监听器,实现ServletRequestListener接口
package org.xxxx.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; public class RequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) { System.out.println("request被销毁了"); } @Override public void requestInitialized(ServletRequestEvent sre) { System.out.println("request被创建了"); } }
b.web.xml配置监听器
<!-- 配置监听器 --> <listener> <listener-class>org.xxxx.listener.RequestListener</listener-class> </listener>
c.创建一个Servlet(自行创建)
d.运行服务器,请求这个Servlet,观察控制台
3.属性变化(session为例)
a.创建监听器类实现HttpSessionAttributeListener接口
package org.xxxx.listener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener { @Override public void sessionCreated(HttpSessionEvent arg0) { System.out.println("session创建了"); } @Override public void sessionDestroyed(HttpSessionEvent arg0) { System.out.println("session销毁了"); } @Override public void attributeAdded(HttpSessionBindingEvent event) { System.out.println("session域里面存数据"); // 获取键和值 String name = event.getName(); Object value = event.getValue(); System.out.println(name + "---" + value); } @Override public void attributeRemoved(HttpSessionBindingEvent event) { System.out.println("session域里面移除数据"); } @Override public void attributeReplaced(HttpSessionBindingEvent event) { System.out.println("session域里面覆盖数据"); } }
b.配置xml
<!-- 配置监听器 --> <listener> <listener-class>org.xxxx.listener.SessionListener</listener-class> </listener>
c.创建Servlet,实现session的创建,移除,覆盖
package org.xxxx.listener; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class MyServlet01 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); // 赋值 session.setAttribute("id", "123"); // 覆盖 session.setAttribute("id", "456"); // 移除 session.removeAttribute("id"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
d.运行服务器,并请求
4.钝化活化,绑定解绑
a.创建监听器类实现HttpSessionActivationListener接口
package org.xxxx.listener; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionEvent; public class SessionListener implements HttpSessionActivationListener { @Override public void sessionDidActivate(HttpSessionEvent se) { System.out.println("session活化了"); } @Override public void sessionWillPassivate(HttpSessionEvent se) { System.out.println("session钝化了"); } }
b.配置xml,同上
c.建立JavaBean和Servlet
Bean实现HttpSessionActivationListener,HttpSessionBindingListener接口
package org.xxxx.listener; import java.io.Serializable; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionEvent; public class Student implements Serializable, HttpSessionActivationListener, HttpSessionBindingListener { private static final long serialVersionUID = 1L; private String name; private int age; public Student() { super(); // TODO Auto-generated constructor stub } public Student(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public void valueBound(HttpSessionBindingEvent event) { System.out.println("javaBean 绑定"); } @Override public void valueUnbound(HttpSessionBindingEvent event) { System.out.println("javaBean解绑"); } @Override public void sessionDidActivate(HttpSessionEvent se) { System.out.println("活化"); } @Override public void sessionWillPassivate(HttpSessionEvent se) { System.out.println("钝化"); } }
Servlet
package org.xxxx.listener; 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 MyServlet02 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Student s = new Student("张三", 20); request.getSession().setAttribute("bean", s); request.getSession().removeAttribute("bean"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
d.运行服务器,观察控制台
e.屏蔽掉request.getSession().removeAttribute("bean");
重新运行,关闭服务器,再开启,分别观察
1)关闭服务器
2)再次开启服务器
5.应用
监控客户端,如果一定时间内没有任何操作,将javabean钝化到硬盘,节省资源
当客户再次操作时,再将javabean活化到session中
在项目/mate-info下配置一个context.xml
运行服务器,请求服务器,一分钟内不要动鼠标,观察控制台<Context> <!-- maxIdleSwap :1分钟 如果session不使用就会序列化到硬盘. directory :westos 序列化到硬盘的文件存放的位置. --> <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"> <Store className="org.apache.catalina.session.FileStore" directory="westos" /> </Manager> </Context>
D.过滤器
1.filter
接口,过滤请求和响应
步骤
a.编写一个类,实现filter重写三个方法
b.编写配置文件,注册filter绑定路径
c.url-pattern配置(和servlet一样)
一个路径匹配到多个filter的时候,执行顺序有有web.xml中filter-mapping的顺序来决定的
d.FilterChain
必须放行才有可能到下一个Filter或者资源上
2.Filter接口方法
init(FilterConfig config):初始化操作
doFilter(ServletRequest request, ServletResponse response, FilterChain chain):处理业务逻辑
destroy() :销毁操作
Servletpackage org.xxxx.demo; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class MyFilter implements Filter { @Override public void destroy() { // 服务器正常关闭,过滤器对象销毁 System.out.println("过滤器被销毁了"); } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { System.out.println("myFilter1过滤器收到请求了"); // 我过滤器只有放行了以后,你servlet才能收到请求 arg2.doFilter(arg0, arg1); System.out.println("myFilter1收到响应了"); } @Override public void init(FilterConfig arg0) throws ServletException { // 服务器一开启,会通过反射创建其子类对象 System.out.println("过滤器被创建了"); // 一般在这里我们会做一些初始化的事情 String value = arg0.getInitParameter("name"); System.out.println(value); } }
package org.xxxx.demo; 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 MyServlet01 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Serlvet收到请求了"); response.getWriter().write("Hello Filter"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
xml(/*是拦截所有服务器请求)
运行服务器<filter> <filter-name>myfilter1</filter-name> <filter-class>org.xxxx.demo.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>myfilter1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
网页
3.FilterChain:过滤链
通过chain的dofilter方法,可以将请求放行到下一个过滤器
直到最后一个过滤器放行才可以访问到servlet|jsp
增加一个过滤器和Servlet
配置xmlpackage org.xxxx.demo; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class MyFilter02 implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("myFilter2 收到请求"); chain.doFilter(request, response); System.out.println("myfiter2 收到响应了"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } }
<filter> <filter-name>myfilter1</filter-name> <filter-class>org.xxxx.demo.MyFilter</filter-class> </filter> <filter> <filter-name>myfilter2</filter-name> <filter-class>org.xxxx.demo.MyFilter02</filter-class> </filter> <filter-mapping> <filter-name>myfilter1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>myfilter2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Servlet(可以多建几个)
运行服务器(分别请求两个服务器)package org.xxxx.demo; 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 MyServlet02 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("MyServlet2 收到请求了"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
4.url-pattern配置
完全匹配:必须以"/" 开始 例如: /a/b
目录匹配:必须以"/" 开始 以"*"结束 例如:/a/b/*
后缀名匹配:以"*."开始 以字符结束 例如 : *.jsp *.do *.action
注意:一个资源有可能被多个过滤器匹配成功
多个过滤器的执行顺序是按照web.xml中filter-mapping的顺序执行的
5.应用:
a.自动登录功能
1)建立数据库和表
2)web项目
jar包 工具类 配置文件
3)新建一个登录页面 表单
登陆
<body> <form action="/AutoLogin/login" method="post"> 用户名:<input type="text" name="username"></input><br> 密码<input type="" name="password"></input><br> 自动登录:<input type="checkbox" name="rember" /><br> <input type="submit" value="登录" /> </form> </body>
登陆成功
<body> <c:if test="${not empty user}"> ${user.username}!!!欢迎你 </c:if> <c:if test="${empty user}"> 你尚未登录 </c:if> </body>
4)表单提交 loginservlet
接受用户名和密码
调用service完成登录操作,返回值User
判断user是否为空
若不为空,将user放入session中
判断是否勾选了自动登录
若勾选了:
需要将用户名和密码写回浏览器
Bean
public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
LoginService
import java.sql.SQLException; import org.westos.demo.bean.User; import org.westos.demo.dao.LoginDao; public class LoginService { public User findUser(String username, String password) throws SQLException { User u=new LoginDao().findUser(username, password); return u; } }
JDBCUtils
import java.sql.Connection; import org.apache.commons.dbutils.QueryRunner; import com.mchange.v2.c3p0.ComboPooledDataSource; public class JDBCUtils { static ComboPooledDataSource ds = null; static { ds = new ComboPooledDataSource(); } public static QueryRunner getRuuner() { QueryRunner runner = new QueryRunner(ds); return runner; } }
LoginDao
import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.westos.demo.JDBCUtils; import org.westos.demo.bean.User; public class LoginDao { public User findUser(String username, String password) throws SQLException { QueryRunner ruuner = JDBCUtils.getRuuner(); String sql = "select * from user2 where username=? and password=?"; User u = null; u = ruuner.query(sql, new BeanHandler<User>(User.class), username, password); return u; } }
LoginServlet
import java.io.IOException; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.westos.demo.bean.User; import org.westos.demo.service.LoginService; public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); User user = new LoginService().findUser(username, password); if (user != null) { // 判断用户是否勾选记住密码 if (request.getParameter("rember") != null) { Cookie uc = new Cookie("username", user.getUsername()); Cookie pc = new Cookie("password", user.getPassword()); uc.setMaxAge(60 * 60 * 24 * 7); pc.setMaxAge(60 * 60 * 24 * 7); // 添加cookie response.addCookie(uc); response.addCookie(pc); } request.getSession().setAttribute("user", user); response.sendRedirect(request.getContextPath() + "/home.jsp"); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
5)下次访问网站的时候
过滤器拦截任意请求
首先判断session中是否有user
若没有 并且访问的路径不是和登录注册相关
判断有无指定的cookie
有cookie,获取用户名和密码
调用service完成登录操作,返回user
当user不为空的时候将user放入session中
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.westos.demo.bean.User; import org.westos.demo.service.LoginService; public class LoginFilter implements Filter { public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 过滤器去查后台 // 读取 Cookie // 向下转型 HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; // 判断有没有登录 User u = (User) req.getSession().getAttribute("user"); if (u == null) {// 没有登录过才自动登录 // 对于某些不需要自动登录的页面,也做一个判断 if (!req.getRequestURI().contains("regiter.jsp")) { Cookie[] cookies = req.getCookies(); String username = ""; String password = ""; if (cookies != null) { for (Cookie c : cookies) { if (c.getName().equals("username")) { username = c.getValue(); } if (c.getName().equals("password")) { password = c.getValue(); } } } // 调用service try { User user = new LoginService().findUser(username, password); if (user != null) { req.getSession().setAttribute("user", user); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } chain.doFilter(req, resp);// 放行 } public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
b.设置编码(不需要每个Srervlet都设置编码)
filter 配置路径/* 过滤器的第一个位置
在filter中重写getParameter(加强)
方法加强:
1.继承(获取构造器)
2.装饰者模式(静态代理)
3.动态代理
装饰者书写步骤
1.要求装饰者和被装饰者实现同一个接口或者继承同一个类
2.装饰者中要有被装饰者的引用
3.对需要加强方法进行加强
4.对不需要加强的方法调用原来的方法即可
过滤器中的代码public class MyRequest extends HttpServletRequestWrapper { HttpServletRequest request; public MyRequest(HttpServletRequest request) { super(request); this.request = request; } // 重新此方法 @Override public String getParameter(String name) { try { // 获取请求方式 String method = request.getMethod(); if (method.equals("GET")) { // get请求 String value = request.getParameter(name); // tomcat8.5以下需要转码,8.5以上直接返回即可 value = new String(name.getBytes("ISO-8859-1"), "utf-8"); return value; } else if (method.equals("POST")) { // post请求 request.setCharacterEncoding("utf-8"); String value = request.getParameter(name); return value; } } catch (Exception e) { e.printStackTrace(); } return super.getParameter(name); } }
5.注意:获取参数的方法有三种,另外两种设置方式一样public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 向下转型 HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; // 放行 chain.doFilter(new MyRequest(req), resp); }
String getParameter(String name);
String[] getParameterValues(String name);
Map<String,String[]> getParameterMap();