【左京淳的JAVA WEB学习笔记】第五章 过滤器与监听器

过滤器可以用来做权限校验或是编码转换等功能。
多个过滤器可以串联在一起,做多重过滤。
自定义的过滤器需实现javax.servlet.Filter介面。

编码转换案例:

  1. 设定过滤范围及encoding方式
@WebFilter(urlPatterns = "/*",
  initParams = {@WebInitParam(name = "encoding",value = "utf-8")})
public class CharacterEncodingFilter implements Filter {…}

urlPatterns = "/*" //过滤目标为此网站下所有网页
initParams = {@WebInitParam(name = "encoding",value = "utf-8")} //将encoding方式设为utf-8(或其他编码)
  1. 在init方法中读取参数
  public void init(FilterConfig fConfig) throws ServletException {
    this.encoding = fConfig.getInitParameter("encoding");
  }
  1. 在doFilter中过滤请求
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    if(encoding != null) {
      request.setCharacterEncoding(encoding);
    }
    HttpServletRequest r = (HttpServletRequest)request;
    if(r.getMethod().equalsIgnoreCase("get")) { //只针对GET请求进行过滤,POST方法通常不会乱码。
      Enumeration<?>names = request.getParameterNames();
      while(names.hasMoreElements()) {
        String[] values = request.getParameterValues(names.nextElement().toString());
        for(int i = 0;i < values.length; ++i) {
          values[i] = new String(values[i].getBytes("ISO-8859-1"),encoding);
        }
      }
    }
    chain.doFilter(request, response); //过滤器处理完後丢给下一个过滤器或引导至资源网页。
  }

权限校验案例:

  1. 用户登入成功後,将用户保存至session中。
    将之前写的LoginSvl稍作修正,原本把用户名保存在request,这次保存到session里面
@WebServlet("/LoginSvl")
public class LoginSvl extends HttpServlet {
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String uname = request.getParameter("uname");
    request.getSession().setAttribute("uname", uname);
    String pwd = request.getParameter("pwd");
    //request.setAttribute("uname", uname);
    request.getRequestDispatcher("/main/hello.jsp").forward(request, response);
  }
}
  1. 定义用户权限过滤器
@WebFilter(filterName = "/UserFilter", urlPatterns = "/user/*")
public class UserFilter implements Filter {
  (前略…)
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest)request;
    Object object = req.getSession().getAttribute("uname");
    if(object != null) { //这边因为是范例,所以没有从资料库拿使用者名单,只是简单的从session里确认是否有uname被储存了。
      chain.doFilter(request, response);
    }else {
      request.setAttribute("msg", "请先登录");
      req.getRequestDispatcher("/main/login.jsp").forward(request, response);
    }
  }
}
  1. 制作jsp页面
    新增user/UserInfo.jsp页面,随意添加一行内容。
Hi,${uname}

跑看看过滤器是否起作用吧。

监听器的种类繁多,用来监听各种不同对象。不像Filter一样只有一种。例如:

ServletContextListener

当服务器启动时会创建ServletContext物件,此时利用监听器即可加载一些初始化资讯。

@WebListener
public class MyContextListener implements ServletContextListener {}
    public void contextDestroyed(ServletContextEvent sce)  { 
    
    }
    public void contextInitialized(ServletContextEvent sce)  { 
         System.out.println("Tomcat启动,ServletContext被创建");
    }

HttpSessionListener

一个Session代表一个在线上的用户,因此可以用监听器追踪或管理用户状态。
注:统计用户对象时,如果用户主动登出,Web应用程序会自动创建另一个会话对象,因此线上人数不会变更。只有用户超时未操作时,线上人数才会减少。

聊天室管理

利用监听器也可以踢掉不当发言的使用者,流程如下:

  1. 在自订的HttpSessionListener里新增一个Map来管理所有session
  2. 在LoginSvl里面也新增一个Map,把所有登入後的使用者放进去。
  3. 如果有想踢掉的使用者,先从LoginSvl的Map找出使用者的sessionid,然後用此id找到在监听器map里相对应的session,使其失效即可。
@WebListener
public class OnlineUserListerner implements HttpSessionListener {
  public static Map<String,HttpSession> allUser;
  static {
    allUser = new ConcurrentHashMap<>();
  }
  
    public void sessionCreated(HttpSessionEvent se)  { 
         HttpSession session = se.getSession();
         allUser.put(session.getId(), session);
    }

    public void sessionDestroyed(HttpSessionEvent se)  { 
        HttpSession session = se.getSession();
        allUser.remove(session.getId(), session);
    }
}
@WebServlet("/LoginSvl")
public class LoginSvl extends HttpServlet {
  private Map<String,String> loginedUsers = new ConcurrentHashMap<>();
  (中略…)
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String uname = request.getParameter("uname");
    String pwd = request.getParameter("pwd");
    LoginBiz biz = new LoginBiz();
    User user = biz.login(uname,pwd);
    request.getSession().setAttribute("user", uname);
    loginedUsers.put(uname, request.getSession().getId());
    request.getRequestDispatcher("/main/main.jsp").forward(request, response);
  }
}

踢除某用户的方法

String sessionid = loginedUsers.get(uname);
HttpSession session = OnlineUserListerner.allUser.get(sessionid);
session.invalidate();

ServletRequestListener

监听每一次用户访问纪录,可用於统计网站被访问次数,例如:

@WebListener
public class PageViewListener implements ServletRequestListener {
  AtomicInteger pv;
    public PageViewListener() {
        System.out.println("PageViewListener被建立");
        pv = new AtomicInteger(0);
    }

    public void requestDestroyed(ServletRequestEvent sre)  { 
    }

    public void requestInitialized(ServletRequestEvent sre)  { 
      System.out.println(pv.incrementAndGet());
    }

此监听器在Tomcat启动时被建立
使用AtomicInteger pv当作计数器。
每次收到客户端的request就会触发一次requestInitialized()。


<<:  Day11:while循环

>>:  寻找mail server

Day25 Android - MVP架构(简易)

练习写好架构有助於在将来程序越做越大时,可以比较好维护程序,又或者是其他人看到这只程序的时候,也比较...

GCP VPC防火墙

防火墙 GCP VPC防火墙规则,应用於给定的项目和网络,防火墙规则可以包含IPv4 IPv6 范围...

CSS选择器

前言 CSS选择器可指定你要对那些元素设定CSS属性。 基本选择器 Class 选择器 使用「.」代...

Git 综合笔记

1. 推资料进新分支 (建立新分支 + 推资料进新分支) (1)建立新专案 命名新专案,并记录网址 ...

Day14【Web】网路攻击:域名劫持

域名劫持又称作域名污染 英文有多种称呼方式: DNS hijacking DNS poisoning...