26、Filter一些常见应用(2)(JavaEE笔记)

一、统一全站字符编码

通过配置参数encoding指明使用何种字符编码,以处理html form请求参数的中文问题。
CharacterEncodingFilter.java

package cn.itcast.web.filter;
//解决全站乱码
import java.io.IOException;
import java.nio.charset.Charset;
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 CharacterEncodingFilter implements Filter {
    
    private FilterConfig FilterConfig = null;
    private String defaultCharset = "UTF-8";
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.FilterConfig = filterConfig;

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        String charset = FilterConfig.getInitParameter("charset");
        if(charset == null){
            //如果为空,则表示没有配置编码,使用默认的编码
            charset = defaultCharset;   
        }
        request.setCharacterEncoding(charset);//这样设置只对post方式有效
        response.setCharacterEncoding(charset);
        response.setContentType("text/html;charset=" + charset);
        
        chain.doFilter(request, response);

    }

    @Override
    public void destroy() {
    }
}

配置:web.xml

    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>cn.itcast.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>charset</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
      </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping> 

二、禁止浏览器缓存所有动态页面的过滤器

  • 有3个http响应头字段都可以禁止浏览器缓存当前页面,它们在Servlet中的示例代码如下:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Prama","no-cache");

并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头。

  • Expires数据头:值为GMT时间值,为-1指浏览器不要缓存页面
  • Cache-Control响应头有两个常用值:
  • No-cache:浏览器不要缓存当前页面
  • Max-age:xxx指浏览器缓存页面xxx秒

示例:
NoCacheFilter.java

public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        response.setDateHeader("Expires", -1);
        response.setHeader("cache-control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        
        chain.doFilter(request, response);
    }

配置:

<filter>
    <filter-name>NoCacheFilter</filter-name>
    <filter-class>cn.itcast.web.filter.NoCacheFilter</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>NoCacheFilter</filter-name>
    <servlet-name>*.jsp</servlet-name>
  </filter-mapping>

说明:这里我们不让jsp进行缓存,所以配置的是*.jsp。还有,要注意首先要将请求和响应对象进行转换

三、控制浏览器缓存页面中的静态资源的过滤器

页面中的有些资源是很长时间不变的,比如一些图片或是一些js和css文件,我们可以通过缓存这些资源以提高服务器的性能。

ExpiresFilter.java

package cn.itcast.web.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;

public class ExpiresFilter implements Filter {

    private FilterConfig filterConfig = null;
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //1.获取用户想访问的资源
        String uri = request.getRequestURI();
        
        //2.得到用户想访问的资源的后缀名
        String ext = uri.substring(uri.lastIndexOf(".") + 1);
        
        //3.得到资源需要缓存的时间
        String time = filterConfig.getInitParameter(ext);
        if(time != null){
            long t = Long.parseLong(time)*3600*1000;
            response.setDateHeader("expires", System.currentTimeMillis() + t);//注意:这里一定要是一个long型时间值
            
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}

配置

  <filter>
        <filter-name>ExpiresFilter</filter-name>
        <filter-class>cn.itcast.web.filter.ExpiresFilter</filter-class>
        <init-param>
            <param-name>css</param-name>
            <param-value>4</param-value>
        </init-param>
        <init-param>
            <param-name>jpg</param-name>
            <param-value>4</param-value>
        </init-param>
        <init-param>
            <param-name>js</param-name>
            <param-value>4</param-value>
        </init-param>
     </filter>
      <filter-mapping><!--一个filter对应多个filter-mapping-->
        <filter-name>ExpiresFilter</filter-name>
        <url-pattern>*.jpg</url-pattern>
      </filter-mapping>
      <filter-mapping>
        <filter-name>ExpiresFilter</filter-name>
        <url-pattern>*.css</url-pattern>
      </filter-mapping>
      <filter-mapping>
        <filter-name>ExpiresFilter</filter-name>
        <url-pattern>*.js</url-pattern>
      </filter-mapping>

说明:从上面的例子中可以看到我们可以精确配置一些静态资源缓存活的时间。如果想看到效果,在试验的时候可以先在IE浏览器中清除缓存,Internet选项-->删除(将最上面的保留收藏夹网站…的勾去掉)-->删除,然后设置-查看文件可以看到目录中的缓存内容,对于我们想要缓存的内容我们可以查看其有效时间是否和我们设置的一样。

四、保护执行敏感操作servlet

在实际开发中我们经常把一些执行敏感操作的Servlet映射到一些特殊目录中,并用Filter把这些特殊目录保护起来,限制只能拥有相应的访问权限的用户才能访问这些目录下的资源。从而在我们系统中实现一种URL级别的权限功能。

要求:为使Filter具有通用性,Filter保护的资源和相应的访问权限通过Filter参数的形式予以配置。(以后会讲到,这里提一下)

五、实现用户自动登录的过滤器

  • 在用户登录成功后,发送一个名称为user的cookie给客户端,cookie的值为用户名和md5加密后的密码。

  • 编写一个AutoLoginFilter,这个Filter检查用户是否带有名称为user的cookie来,如果有,则调用dao查询cookie的用户名和密码是否和数据库中的匹配,匹配则向session中存入user对象(即用户登录标记),以实现程序完成自动登录。

过滤器:AutoLoginFilter.java

package cn.itcast.web.filter;
import java.io.IOException;
import java.net.CookieStore;
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 cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import cn.itcast.utils.WebUtils;

public class AutoLoginFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        
        if(request.getSession().getAttribute("user") != null){//表示已经登录了
            chain.doFilter(request, response);
            return;
        }
        
        //1.得到用户带来的autologin的cookie
        String value =null;
        Cookie cookies[] = request.getCookies();
        for(int i = 0; cookies != null && i < cookies.length; i++){
            if(cookies[i].getName().equals("autologin")){
                value = cookies[i].getValue();
            }
        }
        //2.得到cookie中的用户名和密码
        if(value != null){
            String username = value.split("\\.")[0];
            String password = value.split("\\.")[1];
            
            //3.调用dao获取用户对应的密码
            UserDao dao = new UserDao();
            User user = dao.find(username);
            String dbpassword = user.getPassword();
            
            //4.检查用户带过来的md5密码和数据库中的密码是否匹配,如果匹配则自动登录
            if(password.equals(WebUtils.md5(dbpassword))){
                request.getSession().setAttribute("user", user);
            }   
        }
        
        chain.doFilter(request, response);  
    }

    @Override
    public void destroy() {
    }
}

说明:程序中可以看到我们会在cookie中存入一个名为autologin的标记,其值是用户名和使用md5加密的密码,使用点号分隔。

配置:

<filter>
    <filter-name>AutoLoginFilter</filter-name>
    <filter-class>cn.itcast.web.filter.AutoLoginFilter</filter-class>
</filter> 
<filter-mapping>
    <filter-name>AutoLoginFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

处理登录业务的servlet:LoginServlet.java

package cn.itcast.web.servlet;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
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 sun.misc.BASE64Encoder;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import cn.itcast.utils.WebUtils;

public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        UserDao dao = new UserDao();
        User user = dao.find(username, password);
        if(user == null){
            request.setAttribute("message", "用户名或密码不对!!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return ;
        }
        request.getSession().setAttribute("user", user);//对session作一个标记
        request.setAttribute("message", "登录成功!!!");
        
        //发送自动登录的cookie
        sendAutoLoginCookie(request,response,user);
        request.getRequestDispatcher("/message.jsp").forward(request, response);
    }

    private void sendAutoLoginCookie(HttpServletRequest request, HttpServletResponse response, User user) {
        
        int logintime = Integer.parseInt(request.getParameter("logintime"));//得到时间值
        Cookie cookie = new Cookie("autologin", user.getUsername() + "." + WebUtils.md5(user.getPassword()));//使用点号进行分割,而BASE64中是没有点号的
        cookie.setMaxAge(logintime);//设置cookie的有效时间
        cookie.setPath("/day18");//设置cookie的有效路径,即day18的所有cookie
        
        response.addCookie(cookie);
    }
    
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

dao层:UserDao.java

package cn.itcast.dao;
import java.util.List;
import cn.itcast.db.MyDb;
import cn.itcast.domain.User;

public class UserDao {
    
    public User find(String username, String password){
        
        List<User> list = MyDb.getAll();
        for(User user : list){
            if(user.getUsername().equals(username) && user.getPassword().equals(password)){
                return user;
            }
        }
    
        return null;
    }
    
    public User find(String username){
        List<User> list = MyDb.getAll();
        for(User user : list){
            if(user.getUsername().equals(username)){
                return user;
            }
        }
        return null;
    }
}

模拟一个数据库:MyDb.java

package cn.itcast.db;
import java.util.ArrayList;
import java.util.List;
import cn.itcast.domain.User;

public class MyDb {
    private static List list = new ArrayList();
    
    static {
        list.add(new User("aaa","111"));
        list.add(new User("bbb","222"));
        list.add(new User("ccc","333"));
    }
    public static List getAll(){
        return list;
    }
}

实体类:User.java

package cn.itcast.domain;
public class User {
    private String username ;
    private String password ;
    
    public User() {
    }
    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }
    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;
    }
}

工具类:WebUtils.java

package cn.itcast.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Encoder;

public class WebUtils {
    public static String md5(String message){
        
        try {
            MessageDigest md = MessageDigest.getInstance("md5");
            byte result[] = md.digest(message.getBytes());
            
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(result);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }   
    }
}

界面:login.jsp

<form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="post">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        有效期:
            <input type="radio" name="logintime" value="3600">1小时
            <input type="radio" name="logintime" value="${10*60}">10分钟
            <input type="radio" name="logintime" value="${5*60}">5分钟
            <br/>
        <input type="submit" value="登录">
    </form>

index.jsp

欢迎你:${user.username }登录

全局消息显示页面:message.jsp

${message}

说明:

  • 试验的时候我们先访问login.jsp进行登录,此时请求经过filter时没有经过任何处理就直接到达了servlet,servlet将提交过的用户名和密码和数据库中数据进行对比,如果有此用户则将此用户存入session,就表示此用户已经登录了。

  • 然后再访问index.jsp,此时经过filter的时候filter发现session中已经有此用户,则直接提交给servlet。

  • 上面是在一次会话中进行的试验,此时我们将浏览器关闭,再次访问index.jsp,此时请求经过过滤器时,过滤器会发现cookie中存在一个autologin的标记,则让此用户自动登录。这是因为用户第一次登录的时候我们的servlet会向cookie中存入一个autologin的标记,只要我们下次登录在我们设置的缓存保存时间之内就会自动登录。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文包括:1、Filter简介2、Filter是如何实现拦截的?3、Filter开发入门4、Filter的生命周期...
    廖少少阅读 7,319评论 3 56
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,352评论 11 349
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,860评论 18 139
  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,425评论 0 10
  • 盛夏的午后,喝了点酒,我又精分了。一个人打开酷我,自唱自嗨。当大脑中感性的小人打败了理性的小人的时候,我变开始犯病...
    王家小易阅读 419评论 0 1