过虑器
1.实现一个最基本的过虑器
1:过虑器只对url(路径)进行过虑。
2:过虑器开发人员来实现。
3:过虑器由于是web的核心组,所以这个filter的实现者也必须要配置到web.xml中。
4:三个生命周期方法:init,destory,doFilter(执行过虑任务)。用户的每次请求,都会执行doFIlter方法,而Init,destory只会执行一次。Init方法执行的时间:在项目启动时,直接初始化Filter的对象,所以会在tomcat启动时执行init方法。
第一步:书写一个类实现Filter接口:
@WebFilter("/OneServlet") public class OneFilter implements Filter { public void destroy() { System.err.println("destroy"+this); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.err.println("正在过滤"+this+":"+request); chain.doFilter(request, response); System.err.println("执行完成"+this+":"+request); } public void init(FilterConfig fConfig) throws ServletException { System.err.println("init"+this); } }
第二步:在web.xml中配置这个过虑器
第三步:测试执行
package cn.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/OneServlet") public class OneServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); System.err.println("这是doGet 方法"); response.getWriter().write("你好 OneServlet"+this+":"+request); } }
2.filter的filter-mapping中的url-pattern的设置
url-pattern的设置:
/* = 对所有url都请求这个servlet。| 都被这个filter过虑.
/ = 只可以给servlet。 - 所有其他的servlet不处理的url都由这个url所指定的servlet处理。默认servlet。
*.jspx = 所有以jspx结束都请求到这个Servlet或是被某个Filter拦截。如http://local:8080/proj/abc.jspx
/jsps/* = 所有路径中以/jsps/开头的都请求到这个servlet或是被某个filter拦截到。
/jsps/*.jspx 错误的:SUN规定*两边不可以同时出现字符。
3.过虑器中的其他配置
如果有jsps/abc.jsp这个页面,则显示这个页面有两种方式:
1:在地址栏请求:http://local:8080/project/jsps/abc.jsp -- 可以被拦截到的,因为:路径符合/jsp/abc.jsp
2:req.getRequestDispathcer(“/jsps/abc.jsp”).forward(req,resp); -
Dipatcher属性:
Request – 默认值,只拦截用户的新的请求。
Forward – 对转发进行拦截。
Include – 对include拦截。
Error - 对错误进行拦截。
<!-- 设置对转发拦截 -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
默认情况下,不用配置就是request.
4.配置过虑器的初始化参数
在filter类中有一个方法:init(FilterConfig config); 而filtetrConfig中包含了从web.xml中读取初始化参数值。
<filter> <filter-name>one</filter-name> <filter-class>cn.itcast.filter.OneFilter</filter-class> <init-param> <param-name>name</param-name> <param-value>张三Jack</param-value> </init-param> <init-param> <param-name>age</param-name> <param-value>88</param-value> </init-param> </filter>
5.过虑器链FilterChain
在filter的配置当中,有两个配置:filter,filter-mapping.Filter-mapping在前,则先执行,在后则后执行。
<filter> <filter-name>first</filter-name> <filter-class>cn.filter.FirstFilter</filter-class> </filter> <filter> <filter-name>second</filter-name> <filter-class>cn.filter.SecondFilter</filter-class> </filter> <filter-mapping> <filter-name>first</filter-name> <url-pattern>/ForServlet</url-pattern> </filter-mapping> <filter-mapping> <filter-name>second</filter-name> <url-pattern>/ForServlet</url-pattern> </filter-mapping>
6.过虑器应用之1-设置request编码
写一个过虑器,对所有url全部过虑,/*.在doFilter方法中,设置request的编码为utf-8。一般情况下,这个过虑器永远是第一个要执行的过虑器。最好是通过配置设置编码。<filter><init-param>…
第一步:实现Filter接口,在doFilter中接收初始化参数,设置编码
public class charFilter implements Filter { private String encoding; public charFilter() { } public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.err.println("---"); request.setCharacterEncoding(encoding); response.setContentType("text/html;charset=utf-8"); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { this.encoding=fConfig.getInitParameter("bm"); } }
第二步:将上面的类配置到web.xml
<filter> <filter-name>char</filter-name> <filter-class>cn.itcast.filter.CharFilter</filter-class> <init-param> <!-- 为了便于配置,在配置文件中设置编码 --> <param-name>bm</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>char</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
对get可以处理中文
在CharFilter中对reuqest进行包装。目的:修改增强getParameter方法,如果是get转码。
第一步:声明包装类:
class MyRequest extends HttpServletRequestWrapper { public MyRequest(HttpServletRequest request) { super(request); } // 增强getParamter @Override public String getParameter(String name) { String val = super.getParameter(name); if (super.getMethod().equals("GET")) { try { val = new String(val.getBytes("ISO-8859-1"), super.getCharacterEncoding()); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return val; } }
第二步:在doFilter方法中,声明包装类的实例
public class CharFilter implements Filter { // 声明编码的成员变量 private String encoding; public void init(FilterConfig config) throws ServletException { encoding = config.getInitParameter("bm"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(encoding); response.setContentType("text/html;charset=" + encoding); // 判断是否需要包装 HttpServletRequest req = (HttpServletRequest) request; if (req.getMethod().equals("GET")) { request = new MyRequest(req); } // 声明包装类的实例 // 放行 chain.doFilter(request, response); } public void destroy() { } }
7.设置某些页面缓存或是不缓存
<% response.setHeader("expires","-1"); response.setHeader("pragma","no-cache"); response.setHeader("cache-control","no-cache"); %>
第一步:实现过虑器接口
package cn.filter;public class CacheFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse resp = (HttpServletResponse) response; resp.setHeader("expires", "-1"); resp.setHeader("pragma", "no-cache"); resp.setHeader("cache-control", "no-cache"); System.err.println("---"); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { } }
第二步:配置过虑器,url-pattern=*.jsp
<!-- 配置控制缓存的filter --> <filter> <filter-name>cache</filter-name> <filter-class>cn.filter.CacheFilter</filter-class> </filter> <filter-mapping> <filter-name>cache</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
第三步:设置对某些页面缓存N天
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse resp = (HttpServletResponse) response; // 计算2天以后的毫秒值 // 日历 Calendar cl = Calendar.getInstance(); // 日历上加2天 cl.add(Calendar.DATE, 2); long time = cl.getTimeInMillis(); resp.setDateHeader("expires", time); // resp.setHeader("expires", "-1"); // resp.setHeader("pragma", "no-cache"); // resp.setHeader("cache-control", "no-cache"); System.err.println("---"); chain.doFilter(request, resp); }
8.生成验证码
@WebServlet("/ImageServlet") public class ImageServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应类型 response.setContentType("image/jpeg"); int width = 60; int height = 30; BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = img.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); g.setFont(new Font("宋体", Font.BOLD, 18)); Random r = new Random(); for (int i = 0; i < 4; i++) { Color c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)); int code = r.nextInt(10); g.setColor(c); g.drawString("" + code, i * 15, 10 + r.nextInt(20)); } for (int i = 0; i < 10; i++) { Color c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)); g.setColor(c); g.drawLine(r.nextInt(60), r.nextInt(30), r.nextInt(60), r.nextInt(30)); } // 图片生效 g.dispose(); // 写到 ImageIO.write(img, "JPEG", response.getOutputStream()); } }
方法一:欺骗浏览器
<img id="img" src="<c:url value='/ImageServlet'/>"></img> <a href="javascript:_chg();">看不清</a> <script type="text/javascript"> function _chg() { var img = document.getElementById("img"); var time = new Date().getTime(); img.src = "<c:url value='/ImageServlet?'/>"+time; } </script>
方法二:图片不缓存
11、验证用户是否已经登录
package cn.itcast.filter; 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; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class LoginFilter implements Filter{ public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //将request强转成htt... HttpServletRequest req = (HttpServletRequest) request; //获取session HttpSession ss = req.getSession(); //从session中获取user if(ss.getAttribute("user")==null){ System.err.println("你还没有登录"); req.getSession().setAttribute("msg", "请你先登录"); //重定向到登录 HttpServletResponse resp = (HttpServletResponse) response; resp.sendRedirect(req.getContextPath()+"/index.jsp"); }else{ //放行 chain.doFilter(request, response); } } public void destroy() { } }
配置到web.xml中且对jsps/*进行过虑:
<filter> <filter-name>login</filter-name> <filter-class>cn.itcast.filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>login</filter-name> <url-pattern>/jsps/*</url-pattern> <url-pattern>/views/*</url-pattern> </filter-mapping>
12、实现自动登录
自动登录,是为了帮助用户多次使用这个网页时,不用再次输入用户名和密码就可以登录。
是指用户将用户的登录信息,人,保存到本地的文件中Cookie中。
Name,value – 声明时 new Cookie(key,value);
Path - 默认值,即为当前保存cookie的这个serlvet所在的路径。
如果Cookie在这样的路径:http://loclhost:8080/project/abc/AServlet
则Cookie的路径为: http://loclhost/project/abc
则说明:
所在在http://loclhost/project/abc目录下的servlet才可以读取这个cookie的值。
如果:
保存Cookie类:http://loclhost:8080/project/a/b/AServlet
则Cookie的默认path为;
http://loclhost/project/a/b
对于path这个值可以手工设置:
如果设置为: http://loclhost/project/ 即到项目名。
则所有这个项目中的所有Serlvet|jsp都可以读取到这个 cookie.
Cookie.setPath(requst.getContextPath());
如果将path设置为 /
即:cookie.setpath(“/”); - http://localhost/
则所有在tomcat中运行的项目都可以读取这个到cookie.
如果path设置为/必须要与domain共同使用才有意义。
Age - 默认值-1,在浏览器中存在。 0:删除文件中的cookie和浏览器中的cookie。
Domain - 域 -
www.sina.com - login
www.bbs.sina.com
www.news.sina.com
删除时,必须要设置的与之前设置的信息完全一样:
Name
Age = 0(文件和缓存),-1(只删除文件)
Path 一样。
Domain :null
下一次用户再打开这个网页时,应该读取cookie中的信息,实现自动登录。
13、实现用户自动登录:
第一步:开发一个登录页面
<c:choose> <c:when test="${empty sessionScope.name}"> <form name="x" method="post" action="<c:url value='/LoginServlet'/>"> Name:<input type="text" name="name"/><br/> auto: <input type="radio" name="auto" value="-1">不自动登录 <br/> <input type="radio" name="auto" value="1">1天<br/> <input type="radio" name="auto" value="7">1周<br/> <input type="submit"/> </form> </c:when> <c:otherwise> 你已经登录了:${name}<br/> <a href="<c:url value='/LoginServlet'/>">退出</a> </c:otherwise> </c:choose>
第二步:成功保存cookie
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //接收用户姓名 String name = request.getParameter("name"); String auto = request.getParameter("auto"); //将用户信息放到session request.getSession().setAttribute("name",name); //判断auto是否是-1 if(!auto.equals("-1")){ int day = Integer.parseInt(auto);//1|7 int seconds = 60*60*24*day; //声明cookie Cookie c = new Cookie("autoLogin",name); c.setMaxAge(seconds); c.setPath(request.getContextPath()); //保存cookie response.addCookie(c); } }
第三步:要求访问本网点中任何一个页面都应该实现自动登录
写一个过虑器,对所有url=/*进行过虑。在doFilter中读取所有cookie。是否存在名称为autoLogin的名称cookie。永远都放行。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //在这儿读取cookie HttpServletRequest req = (HttpServletRequest) request; //获取所的有cookie Cookie[] cs = req.getCookies(); if(cs!=null){ for(Cookie c:cs){ if(c.getName().equals("autoLogin")){//如果存在自动登录的cookie String value = c.getValue();//用户名称 //登录成功是指 req.getSession().setAttribute("name", value); break; } } } //不管是否自动登录成 chain.doFilter(request, response); }
第四涉:配置到web.xml中对所有url=/*
<filter> <filter-name>auto</filter-name> <filter-class>cn.itcast.filter.AutoFilter</filter-class> </filter> <filter-mapping> <filter-name>auto</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
第五步:开发退出
System.err.println("用户退出"); //删除整个session request.getSession().invalidate(); Cookie c = new Cookie("autoLogin", "ddd"); c.setMaxAge(0); c.setPath(request.getContextPath()); response.addCookie(c); // request.getSession().removeAttribute("name"); response.sendRedirect(request.getContextPath()+"/index.jsp");
第六步:优化代码
由于用户在做手工登录时,也会进入AutoFiilter的doFilter方法,且读取所有Cookie遍历一次。而这次遍历对用户来说是多余。所以应该将LoginServet这个url在doFiler中不过过虑。且对退出也不能自动登录。