MVC模式设计思想
1、MVC模式概念
MVC模式的全名是Model View Controller,是模型(Model )-视图(View )-控制器(Controller)的缩写。首先要明确的一点是:MVC模式它不是类,也不是什么框架,它只是一种开发的设计思想。将业务逻辑、数据处理、界面显示分别抽取出来统一放到一个地方。从而使同一个程序可以使用不同的表现形式。
MVC的思想就是把我们的程序分为三个核心的模块,这三个模块的详细介绍如下:
- 模型(Model):负责封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。模型层有对数据直接访问的权力,例如对数据库的访问。它不关心它会如何被视图层显示或被控制器调用,它只接受数据并处理,然后返回一个结果。
- 视图(View):负责应用程序对用户的显示,它从用户那里获取输入数据并通过控制层传给业务层处理,然后再通过控制层获取业务层返回的结果并显示给用户。
- 控制器(Controller):负责控制应用程序的流程,它接收从视图层传过来的数据,然后选择Model层中的某个业务来处理,接收Model层返回的结果并选择视图层中的某个视图来显示结果。
我们可以用下图来表示MVC模式中三者之间的关系:
MVC模式的开发没有统一的标准,其中最典型的MVC模式开发思想为:JavaBean+JSP+Servlet。
- JavaBean作为模型,既可以作为数据模型来封装业务数据,又可以作为业务逻辑模型来包含应用的业务操作。其中,数据模型用来存储或传递业务数据,而业务逻辑模型接收到控制器传过来的模型更新请求后,执行特定的业务逻辑处理,然后返回相应的执行结果。
- JSP作为视图,负责提供页面为用户展示数据,提供相应的表单(Form)来用于用户的请求,并在适当的时候(点击按钮)向控制器发出请求来请求模型进行更新。
- Serlvet作为控制器,用来接收用户提交的请求,然后获取请求中的数据,将之转换为业务模型需要的数据模型,然后调用业务模型相应的业务方法进行更新,同时根据业务执行结果来选择要返回的视图。
不过我们在实际的开发中会把它们拆分的更细,从而形成entity+dto+dao+service+controller+html结构,其中entity+dto+dao+service为模型层,controller为控制器层,html为视图层。下面简单介绍一下:
类型 | 名称 | 作用 |
---|---|---|
entity | 实体类 | 一般与数据库的表相对应,封装dao层取出来的数据为一个对象,也就是我们常说的pojo,一般只在dao层与service层之间传输。 |
dao | 数据访问层 | 作用是与数据打交道,可以是数据库操作,也可以是文件读写操作,甚至是redis缓存操作,总之与数据操作有关的都放在这里。 |
dto | 数据传输层 | 主要用于远程调用等需要大量传输对象的地方。假如一个表有25个数据,而显示的只要5个,所有没必要将所有的属性都传输过去。 |
service | 业务逻辑层 | 业务逻辑层用于调用dao层,从而处理一下业务逻辑,如拼接SQL,处理事务等。 |
controller | 控制器层 | 接收从视图层传过来的数据,然后选择service层中的某个业务来处理,接收service层返回的结果并选择视图层中的某个视图来显示结果。 |
2、MVC模式的优缺点
MVC模式之所以能够被广泛的使用到系统中,肯定是有它的优势所在,否则的话也不会存活至今。
MVC的优点:
- 降低耦合度:由于模型、视图和控制器各个层都是分离的,这样在某个层需要改变的时候只需要改变相应层中代码即可,而不用关心其它的层。
- 重用性高:我们可以在不同的视图来访问同一个服务器端的代码,例如在主界面我可以查询,而在后台也可以使用相同的查询功能,但返回的数据是一样的。
- 可维护性高:在修改模型的情况下不会影响到视图,反过来,修改视图,也不会影响到模型。
MVC的缺点:
- 完全理解MVC较复杂:实际的项目拆分了很多层,刚开始学习时不知道各个层的作用。记得自己刚刚学习的时候理解了好久。
- 代码量增加:既然将项目拆分成很多模块,就必然会导致代码量的增加、相应地也会增加软件开发的成文,设计的难度也会增加。
- 系统结构复杂:如果系统小一点到没什么,如果是大型系统的话,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。
总之MVC模式开发的优点是大于缺点的。
3、MVC模式的实现
MVC模式的实现:javabean+dao+servlet+jsp实现一个简单的登录功能。
注意:在搞代码是自己遇到了一个问题就是,我明明导入了MySQL的包,但是它还是一直报错com.mysql.jdbc.Driver
找不到,然后百度了好久,说是将MySQL的驱动包复制到Tomcat的lib目录下就可以的,起初我还不信,结果试了一下居然成功了,也不再是为什么。还是自己太菜了。
①、创建一个名为user的数据库,然后创建一个名为t_user的表,如下:
②、创建视图层页面,login.jsp代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页面</title>
</head>
<body>
<h1 style="color: red;">欢迎您登录系统</h1><hr/>
<div>
<form method="post" action="/login">
<table>
<tr>
<td>Username:</td>
<td><input type="text" name="username" value="${username}"/></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password" value="${password}"/></td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="登录"/>
<input type="reset" value="重置"/>
<span style="color: red">${error}</span>
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
success.jsp代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<div>
<h2>欢迎登陆</h2>
当前登陆的用户为:${currentUser.userName}
</div>
</body>
</html>
③、创建模型层,User实体代码:
package com.thr.entity;
/**
* @author tanghaorong
* @date 2020-05-13
* @desc 模型层
*/
public class User {
private Integer id;
private String userName;
private String password;
//get、set、toSting方法省略
}
对象数据操作的UserDao层代码:
package com.thr.dao;
import com.thr.entity.User;
import java.sql.*;
/**
* @author tanghaorong
* @date 2020-05-13
* @desc 模型层
*/
public class UserDao {
public User login(String username,String password){
//创建JDBC的一些对象
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
User resultUser = null;
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/user?characterEncoding=UTF-8";
String name = "root";
String pwd = "root";
//创建连接
con = DriverManager.getConnection(url, name, pwd);
String sql = "select * from t_user where username = ? and password = ?";
//预编译SQL
ps = con.prepareStatement(sql);
ps.setString(1,username);
ps.setString(2,password);
//执行SQL,并返回结果
rs = ps.executeQuery();
while (rs.next()){
resultUser= new User();
//将结果封装到User对象中
resultUser.setId(rs.getInt(1));
resultUser.setUserName(rs.getString(2));
resultUser.setPassword(rs.getString(3));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭连接
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//返回User对象
return resultUser;
}
}
④、控制器层,UserServlet代码:
package com.thr.controller;
import com.thr.dao.UserDao;
import com.thr.entity.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @author tanghaorong
* @date 2020-05-13
* @desc 控制器层
*/
@WebServlet(name = "UserServlet",value = "/login")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取前端表单发来的数据
String userName=request.getParameter("username");
String password=request.getParameter("password");
//调用Dao模型层,从数据库中去数据
UserDao userDao = new UserDao();
User currentUser=userDao.login(userName, password);
if(currentUser==null){
request.setAttribute("error", "用户名或密码错误");
request.setAttribute("userName", userName);
request.setAttribute("password", password);
request.getRequestDispatcher("login.jsp").forward(request, response);
}else{
HttpSession session=request.getSession();
session.setAttribute("currentUser", currentUser);
response.sendRedirect("success.jsp");
}
}
}
⑤、运行结果,如下所示: