MVC模式简介
在开始介绍这个项目之前,首先我们要知道什么是MVC模式
MVC 模式,全称为 Model-View-Controller(模型-视图-控制器)模式,它是一种软件架构模式,其目标是将软件的用户界面(即前台页面)和业务逻辑分离,使代码具有更高的可扩展性、可复用性、可维护性以及灵活性。
通常情况下,一个完整的 Java Web 应用程序,其结构如下图所示
MVC 模式将应用程序划分成模型(Model)、视图(View)、控制器(Controller)等三层,如下图所示。
MVC 的工作流程如下:
1.用户发送请求到服务器在服务器中,请求被控制层(Controller)接收
2.Controller 调用相应的 Model 层处理请求;
3.Model 层处理完毕将结果返回到 Controller;
4.Controller 再根据 Model 返回的请求处理结果,找到相应的 View 视图;
5.View 视图渲染数据后最终响应给浏览器。
可以说,Controller就是View视图层和Model层之间的桥梁,我们接下来的这个小小项目就用到了MVC思想。
项目概述
总的来说,我们当前的项目有这样几个页面:登录页、注册页、博客列表页、博客详情页、博客编辑页。
登录页
注册页
博客列表页
博客详情页
博客编辑页
功能已经大概流程大概如下:
首先登录注册不用多说
🌰在博客列表页,看到的左侧的用户名必须是我们当前登录的用户名,右侧了博客列表显示的所有用户所写的博客简介。
🌰在博客详情页,我们看到的左侧的用户名是我们当前所查看博客的作者,此外如果这篇博客的作者是当前登录的用户的话,该用户还有权限在博客详情页中删除该博客(删除后就跳转到博客列表页,此时博客列表页已经没有了刚才删除的博客简介),反之则没有权限。
🌰在博客编辑页,当你新写了一篇博客,发布成功后就会跳转到博客列表页,同时在博客列表页的开头就显示出了你刚刚所写的那篇博客的博客简介)
另外,我们要在博客列表页、博客详情页和博客编辑页,检查用户当前的登录状态,如果是为未登录,页面就强制跳转到登录页。
既然我们是按MVC的模式来写的,那么我们就来看看在这个项目中M层、V层和C层都分别做了什么吧!
🍑Model(模型层)
首先对于M层,即我们的模型层。他需要接收C(控制层)对他的调控,完成对数据的操作。
再来看看这张图
我们这个项目需要用到两张表:User用户表和Blog博客表,M层应该有分别对应这两张表的实体类User类和Blog类。另外还应该有对这两张表中数据分别处理的UserDao类、BlogDao类,用来对完成数据的处理(新增、删除、查询等)
🍑View(视图层)
从上图也可以看出,view负责我们用户界面的展示,其实就是前端(HTML、CSS、JS的相关代码)前端把用提交的数据或或者说操作以HTTP请求的方式通过服务器发给我们的Controller(控制器层),然后控制器再对请求做对应的处理,再把处理的结果以相应的形式返回给前端。
🍑Controller(控制器层)
控制器是视图层和模型层之间的桥梁,按前面所说:好像都是控制器层来和视图层(前端)来做交互。那么模型层干什么了呢?
你可不要误会了模型层,他才是处理数据的幕后之人,我们的控制器层只是把视图层(用户)发来的请求,交给模型层来干,同时把模型层辛辛苦苦处理的数据结果返回视图(view)渲染并展示给用户。
在这个过程中,Controller 层不会做任何业务数据上处理,它只是 View(视图)层和 Model (模型)层连接的枢纽,负责调度 View 层和 Model 层,将用户界面和业务逻辑合理的组织在一起,起粘合剂的效果。
光说他们三个之间的关系可能还不清楚,让我们来举例说明
这个我们博客系统实际这三个层所处的位置关系,比如我们现在在进入了博客列表页, 前端(我们的视图层)发来了一个请求要我们返回当前数据库里所有的数据。于是我们的控制层(BlogServlet)代码接收了这个请求,并调用了我们的模型层(BlogDao)让我们的模型层处理了这个数据(在数据库中进行了相关的增删查改)。之后呢,控制层就把处理结果返回给视图(view)渲染并展示给用户。
项目实战
我们是通过maven来创建项目的(项目创建的具体流程,以及要引入的包和依赖参看我的上一篇文章servlet实现表白墙
1、创建项目
2、引入依赖
3、创建必要目录
4、编写代码
5和6、打包和部署:配置Smart Tomcat
7、测试验证
Model(模型层)
先看看一下项目实现后的目录结构
注意我们上面wepapp/WEB-INF/web.xml这个目录和文件是需要我们自己建的。web.xml里面的内容可以直接复制下面的代码
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> </web-app>
上面pom.xml代码参考
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>BlogSystem</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--引入servlet依赖--> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--引入jackson来操作--> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.4</version> </dependency> <!--引入mysql依赖--> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> </dependencies> <!--指定压缩包的类型--> <packaging>war</packaging> <!--指定压缩包的名称--> <build> <finalName>BlogSystem</finalName> </build> </project>
一、模型层
两部分:
实体类——对应我们数据库中的表
业务处理操作类——对应我们对数据库的操作
🌰User代码:对应数据库中的User表
package mode; // 实体类,每个实体类对应数据库中一张表 public class User { private int userId; // 当前登录的用户id private String username; // 用户名字 private String password; // 但注意我们这个属性并没有放在数据库中,因为这个是随时都会改变的(随着你当前所查看博客的不同、当前登录用户的不同) private int isYourBlog; // 通过这个属性,在博客详情页,我们判断是否能够删除该博客 public int getIsYourBlog() { return isYourBlog; } public void setIsYourBlog(int isYourBlog) { this.isYourBlog = isYourBlog; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } 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; } }
🌰Blog类:对应数据库中的Blog表
package mode; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.SimpleTimeZone; // 实体类是我们进行增删改查的基本单位 // 这个对象的实例就表示一篇博客 public class Blog { private int blogId; // 博客id private String title; private String content; private int userId; // 这篇博客的作者的id private Timestamp postTime; public int getBlogId() { return blogId; } public void setBlogId(int blogId) { this.blogId = blogId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } // // 这里返回的不再是一个时间戳,而是格式化好的String // public String getDatetime() { // // return datetime; 如果我们不改这里返回的是一个时间戳,而不是格式化好的时间 // // Java中SimpleDateFormat类就可以 进行时间格式的转换,但需要我们在构造方法中指定转换的时间格式 // SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // return simpleDateFormat.format(this.postTime); // } // 把这个方法魔改一下!! 在方法里面把时间戳构造成格式化时间. 以 String 的方式来返回. public String getPostTime() { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return simpleDateFormat.format(this.postTime); } public void setPostTime(Timestamp postTime) { this.postTime = postTime; } }