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"); } } }
⑤、运行结果