过虑器

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中不过过虑。且对退出也不能自动登录。

原文地址:https://www.cnblogs.com/sunhan/p/3542130.html