[Java]JavaWeb学习笔记(动力节点老杜2022)【Javaweb+MVC架构模式完结】(九)

简介: [Java]JavaWeb学习笔记(动力节点老杜2022)【Javaweb+MVC架构模式完结】(九)

🥽 使用过滤器改造OA项目。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
  <welcome-file-list>
    <welcome-file>welcome</welcome-file>
  </welcome-file-list>
  <!-- 登录验证过滤器 -->
  <filter>
    <filter-name>loginFilter</filter-name>
    <filter-class>cw.javaweb.oa.filter.LoginFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>loginFilter</filter-name>
    <!-- 部门相关的操作需要进行登录验证 -->
    <url-pattern>/dept/*</url-pattern>
  </filter-mapping>
</web-app>
package cw.javaweb.oa.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        // 请求与响应对象进行强转
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 进行登录验证
        // 获取session对象,这里只是进行验证,如果没有session对象不需要创建
        HttpSession session = request.getSession();
        // 获取用户登录证明
        Object username = session.getAttribute("username");
        if (session != null && username != null) {
            // 验证通过
            filterChain.doFilter(request, response);
        } else {
            // 跳转到index页面
            response.sendRedirect(request.getContextPath());
        }
    }
    @Override
    public void destroy() {
    }
}
@WebServlet({"/dept/list", "/dept/detail", "/dept/modify", "/dept/delete", "/dept/add"})
public class DeptServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取servlet路径
        String servletPath = request.getServletPath();
        if ("/dept/list".equals(servletPath)) {
            doList(request, response);
        } else if ("/dept/detail".equals(servletPath)) {
            doDetail(request, response);
        } else if ("/dept/modify".equals(servletPath)) {
            doModify(request, response);
        } else if ("/dept/delete".equals(servletPath)) {
            doDel(request, response);
        } else if ("/dept/add".equals(servletPath)) {
            doAdd(request, response);
        }
    }
    ......
}

🥽 Listener监听器

  • 什么是监听器?
  • 监听器是Servlet规范中的一员。就像Filter一样。Filter也是Servlet规范中的一员。
  • 在Servlet中,所有的监听器接口都是以“Listener”结尾。
  • 监听器有什么用?
  • 监听器实际上是Servlet规范留给我们javaweb程序员的特殊时机。
  • 特殊的时刻如果想执行这段代码,你需要想到使用对应的监听器。
  • Servlet规范中提供了哪些监听器?
  • jakarta.servlet包下:
  • ServletContextListener
  • ServletContextAttributeListener
  • ServletRequestListener
  • ServletRequestAttributeListener
  • jakarta.servlet.http包下:
  • HttpSessionListener
  • HttpSessionAttributeListener
  • 该监听器需要使用@WebListener注解进行标注。
  • 该监听器监听的是什么?是session域中数据的变化。只要数据变化,则执行相应的方法。主要监测点在session域对象上。
package com.bjpowernode.javaweb.listener;
import jakarta.servlet.annotation.WebListener;
import jakarta.servlet.http.HttpSessionAttributeListener;
import jakarta.servlet.http.HttpSessionBindingEvent;
@WebListener
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {
    // 向session域当中存储数据的时候,以下方法被WEB服务器调用。
    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("session data add");
    }
    // 将session域当中存储的数据删除的时候,以下方法被WEB服务器调用。
    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("session data remove");
    }
    // session域当中的某个数据被替换的时候,以下方法被WEB服务器调用。
    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        System.out.println("session data replace");
    }
}
  • HttpSessionBindingListener
  • 该监听器不需要使用@WebListener进行标注。
  • 假设User类实现了该监听器,那么User对象在被放入session的时候触发bind事件,User对象从session中删除的时候,触发unbind事件。
  • 假设Customer类没有实现该监听器,那么Customer对象放入session或者从session删除的时候,不会触发bind和unbind事件。
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;
/**
 * 普通的java类。但是它实现了:HttpSessionBindingListener
 */
public class User1 implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("绑定数据");
    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("解绑数据");
    }
    private String usercode;
    private String username;
    private String password;
    public User1(String usercode, String username, String password) {
        this.usercode = usercode;
        this.username = username;
        this.password = password;
    }
    public User1() {
    }
    public String getUsercode() {
        return usercode;
    }
    public void setUsercode(String usercode) {
        this.usercode = usercode;
    }
    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;
    }
}
  • HttpSessionIdListener
  • session的id发生改变的时候,监听器中的唯一一个方法就会被调用。
  • HttpSessionActivationListener
  • 监听session对象的钝化和活化的。
  • 钝化:session对象从内存存储到硬盘文件。
  • 活化:从硬盘文件把session恢复到内存。
  • 实现一个监听器的步骤:以ServletContextListener为例。
  • 第一步:编写一个类实现ServletContextListener接口。并且实现里面的方法。
在ServletContext对象被创建的时候调用
void contextInitialized(ServletContextEvent event)
在ServletContext对象被销毁的时候调用
void contextDestroyed(ServletContextEvent event)
  • 第二步:在web.xml文件中对ServletContextListener进行配置,如下:
<listener>
    <listener-class>com.bjpowernode.javaweb.listener.MyServletContextListener</listener-class>
</listener>
  • 当然,第二步也可以不使用配置文件,也可以用注解,例如:@WebListener
  • 注意:所有监听器中的方法都是不需要javaweb程序员调用的,由服务器来负责调用?什么时候被调用呢?
  • 当某个特殊的事件发生(特殊的事件发生其实就是某个时机到了。)之后,被web服务器自动调用。
  • 思考一个业务场景:
  • 请编写一个功能,记录该网站实时的在线用户的个数。
  • 我们可以通过服务器端有没有分配session对象,因为一个session代表了一个用户。有一个session就代表有一个用户。如果你采用这种逻辑去实现的话,session有多少个,在线用户就有多少个。这种方式的话:HttpSessionListener够用了。session对象只要新建,则count++,然后将count存储到ServletContext域当中,在页面展示在线人数即可。有会话但是不一定登录在线。
  • 业务发生改变了,只统计登录的用户的在线数量,这个该怎么办?
  • session.setAttribute(“user”, userObj);
  • 用户登录的标志是什么?session中曾经存储过User类型的对象。那么这个时候可以让User类型的对象实现HttpSessionBindingListener监听器,只要User类型对象存储到session域中,则count++,然后将count++存储到ServletContext对象中。页面展示在线人数即可。

🥽 实现oa项目中当前登录在线的人数。

  • 什么代表着用户登录了?
  • session.setAttribute(“user”, userObj); User类型的对象只要往session中存储过,表示有新用户登录。
  • 什么代表着用户退出了?
  • session.removeAttribute(“user”); User类型的对象从session域中移除了。
  • 或者有可能是session销毁了。(session超时)
package com.bjpowernode.oa.bean;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;
public class User implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        // 用户登录了
        // User类型的对象向session中存放了。
        // 获取ServletContext对象
        ServletContext application = event.getSession().getServletContext();
        // 获取在线人数。
        Object onlinecount = application.getAttribute("onlinecount");
        if (onlinecount == null) {
            application.setAttribute("onlinecount", 1);
        } else {
            int count = (Integer)onlinecount;
            count++;
            application.setAttribute("onlinecount", count);
        }
    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        // 用户退出了
        // User类型的对象从session域中删除了。
        ServletContext application = event.getSession().getServletContext();
        Integer onlinecount = (Integer)application.getAttribute("onlinecount");
        onlinecount--;
        application.setAttribute("onlinecount", onlinecount);
    }
    private String username;
    private String password;
    public User() {
    }
    public User(String username, String password) {
        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;
    }
}
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.bean.User;
import com.bjpowernode.oa.utils.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// Servlet负责业务的处理
// JSP负责页面的展示。
@WebServlet({"/user/login","/user/exit"})
public class UserServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String servletPath = request.getServletPath();
        if("/user/login".equals(servletPath)){
            doLogin(request, response);
        }else if("/user/exit".equals(servletPath)){
            doExit(request, response);
        }
    }
    protected void doExit(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取session对象,销毁session
        HttpSession session = request.getSession(false);
        if (session != null) {
            // 从session域中删除user对象
            session.removeAttribute("user");
            // 手动销毁session对象。
            session.invalidate();
            // 销毁cookie(退出系统将所有的cookie全部销毁)
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    // 设置cookie的有效期为0,表示删除该cookie
                    cookie.setMaxAge(0);
                    // 设置一个下cookie的路径
                    cookie.setPath(request.getContextPath()); // 删除cookie的时候注意路径问题。
                    // 响应cookie给浏览器,浏览器端会将之前的cookie覆盖。
                    response.addCookie(cookie);
                }
            }
            // 换一种方案
            /*Cookie cookie1 = new Cookie("username","");
            cookie1.setMaxAge(0);
            cookie1.setPath(request.getContextPath());
            Cookie cookie2 = new Cookie("password", "");
            cookie2.setMaxAge(0);
            cookie2.setPath(request.getContextPath());
            response.addCookie(cookie1);
            response.addCookie(cookie2);*/
            // 跳转到登录页面
            response.sendRedirect(request.getContextPath());
        }
    }
    protected void doLogin(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        boolean success = false;
        // 你要做一件什么事儿?验证用户名和密码是否正确。
        // 获取用户名和密码
        // 前端你是这样提交的:username=admin&password=123
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 连接数据库验证用户名和密码
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = DBUtil.getConnection();
            String sql = "select * from t_user where username = ? and password = ?";
            // 编译SQL
            ps = conn.prepareStatement(sql);
            // 给?传值
            ps.setString(1, username);
            ps.setString(2, password);
            // 执行SQL
            rs = ps.executeQuery();
            // 这个结果集当中最多只有一条数据。
            if (rs.next()) { // 不需要while循环
                // 登录成功
                success = true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, rs);
        }
        // 登录成功/失败
        if (success) {
            // 获取session对象(这里的要求是:必须获取到session,没有session也要新建一个session对象。)
            HttpSession session = request.getSession(); // session对象一定不是null
            //session.setAttribute("username", username);
            User user = new User(username, password);
            session.setAttribute("user", user);
            // 登录成功了,并且用户确实选择了“十天内免登录”功能。
            String f = request.getParameter("f");
            if("1".equals(f)){
                // 创建Cookie对象存储登录名
                Cookie cookie1 = new Cookie("username", username);
                // 创建Cookie对象存储密码
                Cookie cookie2 = new Cookie("password", password); // 真实情况下是加密的。
                // 设置cookie的有效期为十天
                cookie1.setMaxAge(60 * 60 * 24 * 10);
                cookie2.setMaxAge(60 * 60 * 24 * 10);
                // 设置cookie的path(只要访问这个应用,浏览器就一定要携带这两个cookie)
                cookie1.setPath(request.getContextPath());
                cookie2.setPath(request.getContextPath());
                // 响应cookie给浏览器
                response.addCookie(cookie1);
                response.addCookie(cookie2);
            }
            // 成功,跳转到用户列表页面
            response.sendRedirect(request.getContextPath() + "/dept/list");
        } else {
            // 失败,跳转到失败页面
            response.sendRedirect(request.getContextPath() + "/error.jsp");
        }
    }
}

🥽 MVC架构模式

【[Java]MVC架构模式学习笔记(动力节点老杜2022)】

相关文章
|
13天前
|
存储 前端开发 调度
Flux 与传统的 MVC 架构模式区别
Flux是一种用于构建用户界面的架构模式,与传统的MVC架构不同,它采用单向数据流,通过Dispatcher统一管理数据的分发,Store负责存储数据和业务逻辑,View只负责展示数据,使得应用状态更加可预测和易于维护。
|
3月前
|
设计模式 前端开发 数据库
哇塞!Rails 的 MVC 架构也太牛了吧!快来看看这令人惊叹的编程魔法,开启新世界大门!
【8月更文挑战第31天】《Rails中的MVC架构解析》介绍了Ruby on Rails框架核心的MVC设计模式,通过模型(Model)、视图(View)和控制器(Controller)三部分分离应用逻辑,利用Active Record进行数据库操作,ERB模板渲染视图,以及控制器处理用户请求与业务逻辑,使代码更易维护和扩展,提升团队开发效率。
69 0
|
13天前
|
存储 前端开发 数据可视化
在实际项目中,如何选择使用 Flux 架构或传统的 MVC 架构
在实际项目中选择使用Flux架构或传统MVC架构时,需考虑项目复杂度、团队熟悉度和性能需求。Flux适合大型、高并发应用,MVC则适用于中小型、逻辑简单的项目。
|
15天前
|
分布式计算 Java MaxCompute
ODPS MR节点跑graph连通分量计算代码报错java heap space如何解决
任务启动命令:jar -resources odps-graph-connect-family-2.0-SNAPSHOT.jar -classpath ./odps-graph-connect-family-2.0-SNAPSHOT.jar ConnectFamily 若是设置参数该如何设置
|
1月前
|
分布式计算 资源调度 Hadoop
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
76 4
|
1月前
|
分布式计算 Java Hadoop
Hadoop-30 ZooKeeper集群 JavaAPI 客户端 POM Java操作ZK 监听节点 监听数据变化 创建节点 删除节点
Hadoop-30 ZooKeeper集群 JavaAPI 客户端 POM Java操作ZK 监听节点 监听数据变化 创建节点 删除节点
61 1
|
2月前
|
设计模式 前端开发 数据库
理解mvc架构
mvc架构
29 4
|
3月前
|
设计模式 存储 前端开发
MVC革命:如何用一个设计模式重塑你的应用架构,让代码重构变得戏剧性地简单!
【8月更文挑战第22天】自定义MVC(Model-View-Controller)设计模式将应用分为模型、视图和控制器三个核心组件,实现关注点分离,提升代码可维护性和扩展性。模型管理数据和业务逻辑,视图负责数据显示与用户交互,控制器处理用户输入并协调模型与视图。通过示例代码展示了基本的MVC框架实现,可根据需求扩展定制。MVC模式灵活性强,支持单元测试与多人协作,但需注意避免控制器过度复杂化。
42 1
|
3月前
|
开发者 前端开发 Java
架构模式的诗与远方:如何在MVC的田野上,用Struts 2编织Web开发的新篇章
【8月更文挑战第31天】架构模式是软件开发的核心概念,MVC(Model-View-Controller)通过清晰的分层和职责分离,成为广泛采用的模式。随着业务需求的复杂化,Struts 2框架应运而生,继承MVC优点并引入更多功能。本文探讨从MVC到Struts 2的演进,强调架构模式的重要性。MVC将应用程序分为模型、视图和控制器三部分,提高模块化和可维护性。
47 0
|
3月前
|
存储 前端开发 数据库
神秘编程世界惊现强大架构!Web2py 的 MVC 究竟隐藏着怎样的神奇魔力?带你探索实际应用之谜!
【8月更文挑战第31天】在现代 Web 开发中,MVC(Model-View-Controller)架构被广泛应用,将应用程序分为模型、视图和控制器三个部分,有助于提高代码的可维护性、可扩展性和可测试性。Web2py 是一个采用 MVC 架构的 Python Web 框架,其中模型处理数据和业务逻辑,视图负责呈现数据给用户,控制器则协调模型和视图之间的交互。
40 0