【Java Web编程 十四】深入理解MVC架构模式(一)

简介: 【Java Web编程 十四】深入理解MVC架构模式(一)

前面的十一篇博客把JSP和Servlet基本都详细的介绍了一遍,终于,我们的MVC架构模式横空出世,这也是框架诞生前的古早味Web程序的基本设计方式,事实上,即使框架诞生后,也不过是基于MVC模式的扩充和强化,所以理解MVC思想以及MVC早期的实现方式对于后续的框架学习以及理解Web开发的历史有很大的帮助。这篇Blog我将以一个简单的【用户注册登录】实践为主来串联之前十一篇Blog里提到的全部知识,在使用层面为Java Web编程系列划上一个句号。

MVC思想

MVC 全名是 Model View Controller,一种软件设计典范,用一种业务数据、逻辑、界面显示分离的方法组织代码,各部分职责如下:

  • 视图
    视图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由HTML元素组成的界面,在新式的Web应用程序中,HTML依旧在视图中扮演着重要的角色,但是已经被一些能显示动态数据的JSP逐步取代了,MVC好处是它能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,不管这些数据来源是什么,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式
  • 模型
    模型表示企业数据和业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,就是说模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。不能将模型看出一个只有数据的类,其实模型也包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),现在一般会更加细分:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据业务两部分
  • 控制器
    控制器接受用户的输入并调用模型和视图去完成用户的需求,所以当单击Web页面中的超链接和发送HTML表单时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

在前后端不分离的站点中,JSP充当了视图,Servlet充当了控制器,Model充当了模型。抽象意义上的职责如下图所示:

现在的MVC模型已经演化为如下操作过程,下面的整个项目就是依据这样的分层构建的

用户请求会先到达页面,填写信息后进入控制层流转,逻辑处理在Model层做,注意Model层也分两类:

  • Service:处理业务逻辑,这里的Model会返回给前端
  • Dao:处理持久化数据,这里的Model类似POJO,和数据库内的字段一一对应

当然对于我相对简单的一个系统,用一个贯穿的Model就可以了,但最后做解耦,因为落库的字段不一定和请求过来的字段完全一致。

项目构建

其实这个项目是5年前导师交给的一个任务,只完成了前端,当时用的是bootstrap实现的,后端完全没有,这次刚好学习完Java Web就把这部分补充上,项目名称为【黄金找矿网站】。

项目要求

在正式做之前先确定一下项目的要求,要求完成注册登录任务,任务需要满足如下几个要点:

  1. 未登录之前,除了注册登录页面,站点的其它页面均不能访问,请求时都自动跳转到登录页面
  2. 注册用户信息时,需要有前后端验证,对用户提交的表单进行表单验证
  3. 表单验证失败后收集错误信息跳转到错误页面,告知失败原因
  4. 注册成功后跳转到注册成功页面,告知用户的注册信息
  5. 登录时判断库里是否有该用户,只有存在且密码正确才可以登录成功
  6. 点击登出后当前用户恢复未登录状态
  7. 站点开启和关闭时需要加监控,监控服务的运行状态

其实这样一个注册登录项目就是我这两天设计出来用来将历史十一篇blog学习过的技术进行整合的,每个要求都涉及相关知识点。

技术要点

对照上边的实现要求,其实可以能抽象出所有的技术要点:

  1. 未登录之前,除了注册登录页面,站点的其它页面均不能访问,请求时都自动跳转到登录页面【Filter过滤器&重定向&Session作用域
  2. 注册用户信息时,需要有前后端验证,对用户提交的表单进行表单验证【表单提交&表单验证&请求转发&Servlet常用对象
  3. 表单验证失败后收集错误信息跳转到错误页面,告知失败原因【JSTL标签
  4. 注册成功后跳转到注册成功页面,告知用户的注册信息【JSP语法&EL表达式&JavaBean
  5. 登录时判断库里是否有该用户,只有存在且密码正确才可以登录成功【JDBC
  6. 点击登出后当前用户恢复未登录状态【Session销毁
  7. 站点开启和关闭时需要加监控,监控服务的运行状态【Listener监听器

好的,也就是说这个项目可以帮助我和大家复习整体的古早Java Web实现方式。

整体布局

整个项目的整体布局和分层如下:

项目所需的Maven配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>GoldenManage</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>GoldenManage</name>
    <packaging>war</packaging>
    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <junit.version>5.7.1</junit.version>
    </properties>
    <dependencies>
        <!--引入servlet相关依赖,https://repo.maven.apache.org/maven2/javax/servlet/servlet-api/-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <!--引入jsp相关依赖,https://repo.maven.apache.org/maven2/javax/servlet/jsp/jsp-api/-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.2.1</version>
            <scope>provided</scope>
        </dependency>
        <!--引入junit测试引擎相关依赖-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/taglibs/standard -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.1</version>
            </plugin>
        </plugins>
    </build>
</project>

代码清单

罗列下整体项目实现的代码清单吧,其中JSP中用到了前端框架BootStrap,这个就不展开讲了,前端框架一般是在没有前端同学帮助下使用的好利器。

JSP代码清单

JSP分为如下几个页面:login.jsp用于登录,register.jsp用于注册,logout.jsp用于登出,还有两个显示结果的页面:success.jsp和error.jsp,以及显示首页的index.jsp页面

login.jsp

<%--
  Created by IntelliJ IDEA.
  User: 13304
  Date: 2021/7/31
  Time: 16:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>用户登录</title>
    <link rel="shortcut icon" type="image/x-icon" href="images/cugbIcon.ico"/>
    <link rel="stylesheet" href="css/style.css" />
<body>
<div class="login-container">
    <h1>黄金矿工</h1>
    <div class="connect">
        <p>welcome to cugb</p>
    </div>
    <form action="ControlServlet" method="post" id="loginForm">
        <div>
            <input type="text" name="username" class="username" placeholder="用户名" autocomplete="off"/>
        </div>
        <div>
            <input type="password" name="password" class="password" placeholder="密码" oncontextmenu="return false" onpaste="return false" />
        </div>
        <button id="submit" type="submit">登 陆</button>
    </form>
    <a href="register.jsp">
        <button type="button" class="register-tis">注册</button>
    </a>
</div>
<script src="js/jquery.min.js"></script>
<script src="js/common.js"></script>
<!--背景图片自动更换-->
<script src="js/supersized.3.2.7.min.js"></script>
<script src="js/supersized-init.js"></script>
<!--表单验证-->
<script src="js/jquery.validate.min.js?var1.14.0"></script>
</body>
</html>

logout.jsp

<%--
  Created by IntelliJ IDEA.
  User: 13304
  Date: 2021/7/31
  Time: 17:22
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <title>退出登录</title>
  <link rel="shortcut icon" type="image/x-icon" href="images/cugbIcon.ico"/>
  <link rel="stylesheet" href="css/style.css" />
<body>
<div class="login-container">
  <h1>黄金矿工</h1>
  <div class="connect">
    <p>welcome to cugb</p>
  </div>
  <form action="StopServlet" method="get" id="loginForm">
    <button id="submit" type="submit">确认登出</button>
  </form>
</div>
<script src="js/jquery.min.js"></script>
<script src="js/common.js"></script>
<!--背景图片自动更换-->
<script src="js/supersized.3.2.7.min.js"></script>
<script src="js/supersized-init.js"></script>
<!--表单验证-->
<script src="js/jquery.validate.min.js?var1.14.0"></script>
</body>
</html>

register.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>用户注册</title>
    <link rel="stylesheet" href="css/style.css" />
    <link rel="shortcut icon" type="image/x-icon" href="images/cugbIcon.ico"/>
<body>
<div class="register-container">
    <h1>黄金矿工</h1>
    <div class="connect">
        <p>welcome to cugb</p>
    </div>
    <%--onpaste是否运行粘贴;oncontextmenu 是否允许展开右键菜单;placeholder 输入提示;autocomplete是否允许浏览器自动补齐--%>
    <form action="GetPermission" method="post" id="registerForm">
        <div>
            <input type="text" name="name"  placeholder="您的用户名" autocomplete="off" />
        </div>
        <div>
            <input type="password" name="password" class="password" placeholder="输入密码" oncontextmenu="return false" onpaste="return false" />
        </div>
        <div>
            <input type="password" name="confirm_password" class="confirm_password" placeholder="再次输入密码" oncontextmenu="return false" onpaste="return false" />
        </div>
        <div>
            <input type="text" name="phone_number" class="phone_number" placeholder="输入手机号码" autocomplete="off" id="number"/>
        </div>
        <div>
            <input type="email" name="email" class="email" placeholder="输入邮箱地址" oncontextmenu="return false" onpaste="return false" />
        </div>
        <button id="submit" type="submit" style="width: 332px">注 册</button>
    </form>
    <a href="login.jsp">
        <button type="button" class="register-tis" style="width: 332px">返回登录</button>
    </a>
</div>
<script src="js/jquery.min.js"></script>
<!--背景图片自动更换-->
<script src="js/supersized.3.2.7.min.js"></script>
<script src="js/supersized-init.js"></script>
<!--表单验证-->
<script src="js/jquery.validate.min.js?var1.14.0"></script>
<script src="js/common.js"></script>
</body>
</html>
相关文章
|
9天前
|
设计模式 安全 Java
Java编程中的单例模式:理解与实践
【10月更文挑战第31天】在Java的世界里,单例模式是一种优雅的解决方案,它确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的实现方式、使用场景及其优缺点,同时提供代码示例以加深理解。无论你是Java新手还是有经验的开发者,掌握单例模式都将是你技能库中的宝贵财富。
14 2
|
4天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
11天前
|
存储 前端开发 调度
Flux 与传统的 MVC 架构模式区别
Flux是一种用于构建用户界面的架构模式,与传统的MVC架构不同,它采用单向数据流,通过Dispatcher统一管理数据的分发,Store负责存储数据和业务逻辑,View只负责展示数据,使得应用状态更加可预测和易于维护。
|
12天前
|
Java API Apache
Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
【10月更文挑战第29天】Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
60 5
|
6天前
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
87 53
|
6天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
2天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
5天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
13 2
|
6天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
10天前
|
监控 前端开发 JavaScript
探索微前端架构:构建可扩展的现代Web应用
【10月更文挑战第29天】本文探讨了微前端架构的核心概念、优势及实施策略,通过将大型前端应用拆分为多个独立的微应用,提高开发效率、增强可维护性,并支持灵活的技术选型。实际案例包括Spotify和Zalando的成功应用。