超级管理员

79361

帖子

13

回复

238

积分

楼主
发表于 2020-09-30 22:20:03 | 查看: 21 | 回复: 0
/*
 *
 * title: 从面向过程到面向对象再到MVC
 * author: tanghao
 * date: 2020.9.30
 * version: 1.0
 *
 */

前言

本文档通过一个显示2019年英雄联盟半决赛的比赛信息及队伍信息的实例,使用JSP+MySQL从面向过程编程,改写成为面向对象编程,再改写成为MVC的实现模式。利用代码系统地演示从面向过程到面向对象,再到MVC的过程。使你能够初步了解这些编程方法的基本区别一些思想方法。

参考了一篇PHP在这方面的文章。

  • 数据库:test_db
  • 面向过程:test_pop
  • 面向对象:test_oop
  • MVC:test_mvc & test_mvc2

1 数据库

建立数据库

create database if not exists test_db default charset utf8 collate utf8_general_ci;

建立队伍表team、选手表player和比赛表match

# 队伍表 team
CREATE TABLE `team` (
  `t_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '队伍ID',
  `t_name` varchar(255) NOT NULL COMMENT '队名',
  PRIMARY KEY pk_id (`t_id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;

# 选手表 player
CREATE TABLE `player` (
  `p_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '选手ID',
  `p_name` varchar(255) NOT NULL COMMENT '选手姓名',
  `t_id` INT(11) UNSIGNED NOT NULL COMMENT '队伍ID',
  PRIMARY KEY pk_id (`p_id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;

# 比赛表 match
CREATE TABLE `match` (
  `m_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '比赛ID',
  `t1_id` INT(11) UNSIGNED NOT NULL COMMENT '队伍1ID',
  `t2_id` INT(11) UNSIGNED NOT NULL COMMENT '队伍2ID',
  `t1_score` INT(11) UNSIGNED NOT NULL COMMENT '队伍1得分',
  `t2_score` INT(11) UNSIGNED NOT NULL COMMENT '队伍2得分',
  PRIMARY KEY pk_id (`m_id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;

向三张表中添加数据

INSERT INTO 
`team` (`t_id`, `t_name`)
VALUES 
('1', 'IG'),
('2', 'FPX'),
('3', 'SKT'),
('4', 'G2');

INSERT INTO 
`player` (`p_id`, `p_name`, `t_id`)
VALUES 
('1', 'The Shy', '1'),
('2', 'Ning', '1'),
('3', 'Rookie', '1'),
('4', 'JackeyLove', '1'),
('5', 'Baolan', '1'),
('6', 'Gimgoon', '2'),
('7', 'Tian', '2'),
('8', 'Doinb', '2'),
('9', 'Lwx', '2'),
('10', 'Crisp', '2'),
('11', 'Khan', '3'),
('12', 'Clid', '3'),
('13', 'Faker', '3'),
('14', 'Teddy', '3'),
('15', 'Mata', '3'),
('16', 'Wunder', '4'),
('17', 'Jankos', '4'),
('18', 'Caps', '4'),
('19', 'Perkz', '4'),
('20', 'Mikyx', '4');

INSERT INTO 
`match` (`m_id`, `t1_id`, `t2_id`, `t1_score`, `t2_score`)
VALUES 
('1', '1', '2', '1', '3'),
('2', '3', '4', '1', '3');

最终的三张表

2. 面向过程的程序

第一个页面match.jsp,显示比赛信息,具体有队伍1的队名,队伍2的队名,队伍1的得分,队伍2的得分。这些数据需要从match和team表中获取。

先编写SQL语句

SELECT
  t1_team.t_name AS t1_name,
  t2_team.t_name AS t2_name,
  m.t1_score,
  m.t2_score
FROM
  `match` AS m
  LEFT JOIN `team` AS t1_team ON m.t1_id = t1_team.t_id
  LEFT JOIN `team` AS t2_team ON m.t2_id = t2_team.t_id;

然后编写JSP页面

match.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>

<%
  // 数据库连接信息
  String Driver = "com.mysql.jdbc.Driver";
  String url = "jdbc:mysql://localhost:3306/test_db";
  String user = "root";
  String password = "123456";
  
  // 连接数据库
  Class.forName(Driver);
  Connection conn = DriverManager.getConnection(url, user, password);
  
  // SQL查询语句
  String sql = " SELECT "
    + " t1_team.t_name AS t1_name, "
    + " t2_team.t_name AS t2_name, "
    + " m.t1_score, "
    + " m.t2_score "
    + " FROM "
    + " `match` AS m "
    + " LEFT JOIN `team` AS t1_team ON m.t1_id = t1_team.t_id "
    + " LEFT JOIN `team` AS t2_team ON m.t2_id = t2_team.t_id; ";
  
  // 执行SQL语句,返回结果集
  PreparedStatement pst = conn.prepareStatement(sql);
  ResultSet rst = pst.executeQuery();
%>

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>比赛信息</title>
</head>

<body>
  <h1>比赛信息</h1>
  <table border="1">
    <tr>
      <th>队伍1</th>
      <th>队伍2</th>
      <th>队伍1得分</th>
      <th>队伍2得分</th>
    </tr>
    <%
      while (rst.next()) {
    %>
      <tr>
        <td><%=rst.getString("t1_name")%></td>
        <td><%=rst.getString("t2_name")%></td>
        <td><%=rst.getString("t1_score")%></td>
        <td><%=rst.getString("t2_score")%></td>
      </tr>
    <%
      }
    %>
  </table>
</body>

</html>

<%
  // 关闭数据库连接
  rst.close();
  pst.close();
  conn.close();
%>

然后编写第二个页面team.jsp。该页面可以通过第一个页面上的队伍链接跳转到具体的队伍页面,显示队伍中的队员信息。

首先需要对sql进行一点更改,加入队伍的ID信息。

SELECT
	t1_team.t_name AS t1_name,
	t2_team.t_name AS t2_name,
	m.t1_score,
	m.t2_score,
	m.t1_id,
	m.t2_id
FROM
	`match` AS m
	LEFT JOIN `team` AS t1_team ON m.t1_id = t1_team.t_id
	LEFT JOIN `team` AS t2_team ON m.t2_id = t2_team.t_id;

同时在match加入点击队伍的链接。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>

<%
  // 数据库连接信息
  String Driver = "com.mysql.jdbc.Driver";
  String url = "jdbc:mysql://localhost:3306/test_db";
  String user = "root";
  String password = "123456";
  
  // 连接数据库
  Class.forName(Driver);
  Connection conn = DriverManager.getConnection(url, user, password);
  
  // SQL查询语句
  String sql = " SELECT "
    + " t1_team.t_name AS t1_name, "
    + " t2_team.t_name AS t2_name, "
    + " m.t1_score, "
    + " m.t2_score, "
    + " m.t1_id, "
    + " m.t2_id "
    + " FROM "
    + " `match` AS m "
    + " LEFT JOIN `team` AS t1_team ON m.t1_id = t1_team.t_id "
    + " LEFT JOIN `team` AS t2_team ON m.t2_id = t2_team.t_id; ";
  
  // 执行SQL语句,返回结果集
  PreparedStatement pst = conn.prepareStatement(sql);
  ResultSet rst = pst.executeQuery();
%>

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>比赛信息</title>
</head>

<body>
  <h1>比赛信息</h1>
  <table border="1">
    <tr>
      <th>队伍1</th>
      <th>队伍2</th>
      <th>队伍1得分</th>
      <th>队伍2得分</th>
    </tr>
    <%
      while (rst.next()) {
    %>
      <tr>
        <td><a href='team.jsp?t_id=<%=rst.getInt("t1_id")%>'><%=rst.getString("t1_name")%></a></td>
        <td><a href='team.jsp?t_id=<%=rst.getInt("t2_id")%>'><%=rst.getString("t2_name")%></a></td>
        <td><%=rst.getString("t1_score")%></td>
        <td><%=rst.getString("t2_score")%></td>
      </tr>
    <%
      }
    %>
  </table>
</body>

</html>

<%
  // 关闭数据库连接
  rst.close();
  pst.close();
  conn.close();
%>

接下来,编写team.jsp页面。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>

<%
  // 数据库连接信息
  String Driver = "com.mysql.jdbc.Driver";
  String url = "jdbc:mysql://localhost:3306/test_db";
  String user = "root";
  String password = "123456";
  
  // 连接数据库
  Class.forName(Driver);
  Connection conn = DriverManager.getConnection(url, user, password);
  
  // 获取地址栏传递的队伍ID
  String t_id = request.getParameter("t_id");
  
  // SQL查询语句
  String sql1 = " SELECT t_name FROM `team` WHERE t_id = " + t_id + " ; ";
  String sql2 = " SELECT p_name FROM `player` WHERE t_id = " + t_id + " ; ";
  
  // 执行SQL语句,返回结果集
  PreparedStatement pst1 = conn.prepareStatement(sql1);
  ResultSet rst1 = pst1.executeQuery();
  
  // 获取rst1的第一个记录
  String t_name = "";
  if (rst1.next()) {
      t_name = rst1.getString("t_name");
  } 
  
  PreparedStatement pst2 = conn.prepareStatement(sql2);
  ResultSet rst2 = pst2.executeQuery();
%>

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>比赛信息</title>
</head>

<body>
  <h1>队伍信息</h1>
  <h2><%=t_name%></h2>
  <table border="1">
    <tr>
      <th>队员</th>
    </tr>
    <%
      while (rst2.next()) {
    %>
      <tr>
        <td><%=rst2.getString("p_name")%></td>
      </tr>
    <%
      }
    %>
  </table>
</body>

</html>

<%
  // 关闭数据库连接
  rst1.close();
  pst1.close();
  rst2.close();
  pst2.close();
  conn.close();
%>

POP代码的完整演示

面向过程的编程到此结束,下面会介绍如何将这个面向过程的程序改写为面向对象的程序。

3. 面向对象的程序

分析上面的JSP文件中的Java代码部分,会看到操作数据库的代码有很多都是重复的,因此我们可以把操作数据库的代码封装成一个类的方法,方便以后再次使用时,直接调用类的方法即可,实现复用。

DBUtil类

package util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DBUtil {
    // 数据库连接信息
    String Driver = "com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://localhost:3306/test_db";
    String user = "root";
    String password = "123456";
    
    Connection conn;
    PreparedStatement pst;
    ResultSet rst;
    
    // 连接数据库,根据SQL语句返回结果集
    public ResultSet getResultSet(String sql) throws ClassNotFoundException, SQLException {
        Class.forName(Driver);
        conn = DriverManager.getConnection(url, user, password);
        pst = conn.prepareStatement(sql);
        rst = pst.executeQuery();
        return rst;
    }
    
    // 关闭数据库
    public void colse() throws SQLException {
        rst.close();
        pst.close();
        conn.close();
    }
}

改写后的match.jsp

连接数据库获取数据只需要利用DBUtil对象的getResultSet()方法。
关闭数据库只需要利用DBUtil对象的close()方法。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>
<%@ page import="util.DBUtil"%>

<%
  DBUtil dbUtil = new DBUtil();
  
  // SQL查询语句
  String sql = " SELECT "
    + " t1_team.t_name AS t1_name, "
    + " t2_team.t_name AS t2_name, "
    + " m.t1_score, "
    + " m.t2_score, "
    + " m.t1_id, "
    + " m.t2_id "
    + " FROM "
    + " `match` AS m "
    + " LEFT JOIN `team` AS t1_team ON m.t1_id = t1_team.t_id "
    + " LEFT JOIN `team` AS t2_team ON m.t2_id = t2_team.t_id; ";
  
  ResultSet rst = dbUtil.getResultSet(sql); 
%>

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>比赛信息</title>
</head>

<body>
  <h1>比赛信息</h1>
  <table border="1">
    <tr>
      <th>队伍1</th>
      <th>队伍2</th>
      <th>队伍1得分</th>
      <th>队伍2得分</th>
    </tr>
    <%
      while (rst.next()) {
    %>
      <tr>
        <td><a href='team.jsp?t_id=<%=rst.getInt("t1_id")%>'><%=rst.getString("t1_name")%></a></td>
        <td><a href='team.jsp?t_id=<%=rst.getInt("t2_id")%>'><%=rst.getString("t2_name")%></a></td>
        <td><%=rst.getString("t1_score")%></td>
        <td><%=rst.getString("t2_score")%></td>
      </tr>
    <%
      }
    %>
  </table>
</body>

</html>

<%
  // 关闭数据库连接
  dbUtil.colse();
%>

完成之后的页面效果与之前的写法没有任何差别

同理可以对team.jsp页面进行修改

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>
<%@ page import="util.DBUtil"%>

<%
  DBUtil dbUtil = new DBUtil();
  
  // 获取地址栏传递的队伍ID
  String t_id = request.getParameter("t_id");
  
  // SQL查询语句
  String sql1 = " SELECT t_name FROM `team` WHERE t_id = " + t_id + " ; ";
  String sql2 = " SELECT p_name FROM `player` WHERE t_id = " + t_id + " ; ";
  
  // 执行SQL语句,返回结果集
  ResultSet rst1 = dbUtil.getResultSet(sql1);
  ResultSet rst2 = dbUtil.getResultSet(sql2);
  
  // 获取rst1的第一个记录
  String t_name = "";
  if (rst1.next()) {
      t_name = rst1.getString("t_name");
  }
%>

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>比赛信息</title>
</head>

<body>
  <h1>队伍信息</h1>
  <h2><%=t_name%></h2>
  <table border="1">
    <tr>
      <th>队员</th>
    </tr>
    <%
      while (rst2.next()) {
    %>
      <tr>
        <td><%=rst2.getString("p_name")%></td>
      </tr>
    <%
      }
    %>
  </table>
</body>

</html>

<%
  // 关闭数据库连接
  dbUtil.colse();
%>

所以,可以初略简单地认为面向对象是将面向过程中的一些通用共性的代码提取出来,成为类或者对象的方法,方便后面再次书写时直接通过.方法的形式进行使用,利于代码的复用。

OOP代码的完整演示

4. MVC

4.1

在上面的代码中,一个JSP上既有业务逻辑处理,又有视图的展示。以match.jsp页面为例,既要从数据库中取出相应的数据,又要对数据进行前端展示,代码结构略显混乱。

如果要通过MVC的方式进行改造,那么可以将业务逻辑部分单独提取成一个JSP文件——match_m.jsp,视图展示部分也单独提取成一个JSP文件——match_v.jsp,同时新构建一个JSP文件——match_c.jsp将这两个文件联系起来,那么这样就可以做到代码的分离,结构清晰也利于维护。

mathch_m.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>
<%@ page import="util.DBUtil"%>

<%
  DBUtil dbUtil = new DBUtil();
  
  // SQL查询语句
  String sql = " SELECT "
    + " t1_team.t_name AS t1_name, "
    + " t2_team.t_name AS t2_name, "
    + " m.t1_score, "
    + " m.t2_score, "
    + " m.t1_id, "
    + " m.t2_id "
    + " FROM "
    + " `match` AS m "
    + " LEFT JOIN `team` AS t1_team ON m.t1_id = t1_team.t_id "
    + " LEFT JOIN `team` AS t2_team ON m.t2_id = t2_team.t_id; ";
  
  ResultSet rst_m = dbUtil.getResultSet(sql);
  
  request.setAttribute("rst_m", rst_m);
%>

match_v.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>比赛信息</title>
</head>

<body>
  <h1>比赛信息</h1>
  <table border="1">
    <tr>
      <th>队伍1</th>
      <th>队伍2</th>
      <th>队伍1得分</th>
      <th>队伍2得分</th>
    </tr>
    <%
      ResultSet rst_v = (ResultSet)request.getAttribute("rst_m");
      while (rst_v.next()) {
    %>
      <tr>
        <td><a href='team.jsp?t_id=<%=rst_v.getInt("t1_id")%>'><%=rst_v.getString("t1_name")%></a></td>
        <td><a href='team.jsp?t_id=<%=rst_v.getInt("t2_id")%>'><%=rst_v.getString("t2_name")%></a></td>
        <td><%=rst_v.getString("t1_score")%></td>
        <td><%=rst_v.getString("t2_score")%></td>
      </tr>
    <%
      }
    %>
  </table>
</body>

</html>

match_c.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ include file="match_m.jsp" %>

<%@ include file="match_v.jsp" %>

4.2

那么在一般的Javaweb项目开发中
M通常是由实体类和相应的数据库操作组成;
V通常是JSP页面;
C通常是Servlet类。

Match.java

package m;

public class Match {
    
    private String t1Name;
    
    private String t2Name;
    
    private String t1Score;
    
    private String t2Score;

    public String getT1Name() {
        return t1Name;
    }

    public void setT1Name(String t1Name) {
        this.t1Name = t1Name;
    }

    public String getT2Name() {
        return t2Name;
    }

    public void setT2Name(String t2Name) {
        this.t2Name = t2Name;
    }

    public String getT1Score() {
        return t1Score;
    }

    public void setT1Score(String t1Score) {
        this.t1Score = t1Score;
    }

    public String getT2Score() {
        return t2Score;
    }

    public void setT2Score(String t2Score) {
        this.t2Score = t2Score;
    }
}

DBUtil.java

package m;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DBUtil {
    // 数据库连接信息
    String Driver = "com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://localhost:3306/test_db";
    String user = "root";
    String password = "123456";
    
    Connection conn;
    PreparedStatement pst;
    ResultSet rst;
    
    // 连接数据库,根据SQL语句返回结果集
    public ResultSet getResultSet(String sql) throws ClassNotFoundException, SQLException {
        Class.forName(Driver);
        conn = DriverManager.getConnection(url, user, password);
        pst = conn.prepareStatement(sql);
        rst = pst.executeQuery();
        return rst;
    }
    
    // 关闭数据库
    public void colse() throws SQLException {
        rst.close();
        pst.close();
        conn.close();
    }
}

MatchServlet.java

package c;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

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 m.DBUtil;
import m.Match;


@WebServlet("/MatchServlet")
public class MatchServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        List<Match> matchs = new ArrayList<Match>();
        
        DBUtil dbUtil = new DBUtil();
        
        String sql = " SELECT "
                + " t1_team.t_name AS t1_name, "
                + " t2_team.t_name AS t2_name, "
                + " m.t1_score, "
                + " m.t2_score, "
                + " m.t1_id, "
                + " m.t2_id "
                + " FROM "
                + " `match` AS m "
                + " LEFT JOIN `team` AS t1_team ON m.t1_id = t1_team.t_id "
                + " LEFT JOIN `team` AS t2_team ON m.t2_id = t2_team.t_id; ";
        
        ResultSet rst;
        try {
            rst = dbUtil.getResultSet(sql);
            while (rst.next()) {
                Match match = new Match();
                match.setT1Name(rst.getString("t1_name"));
                match.setT2Name(rst.getString("t2_name"));
                match.setT1Score(rst.getString("t1_score"));
                match.setT2Score(rst.getString("t2_score"));
                matchs.add(match);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        request.setAttribute("matchs", matchs);
        request.getRequestDispatcher("/match.jsp").forward(request, response);
    }
}

match.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.sql.*"%>
<%@ page import="m.Match"%>

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>比赛信息</title>
</head>

<body>
  <h1>比赛信息</h1>
  <table border="1">
    <tr>
      <th>队伍1</th>
      <th>队伍2</th>
      <th>队伍1得分</th>
      <th>队伍2得分</th>
    </tr>
    <%
    List<Match> matchs = (ArrayList)request.getAttribute("matchs");
    for (int i = 0; i < matchs.size(); i++) {
        Match match = new Match();
        match = matchs.get(i);
    %>
      <tr>
        <td><%=match.getT1Name()%></td>
        <td><%=match.getT2Name()%></td>
        <td><%=match.getT1Score()%></td>
        <td><%=match.getT2Score()%></td>
      </tr>
    <%
      }
    %>
  </table>
</body>

</html>

最终截图

4.3

MVC继续细分就是JavaEE的经典五层架构了,这里可以直接去参考我的另外一篇博客:
JSP+Servlet+Ajax实现用户增删改查的例子

如果继续下去就是SSH SSM SpringBoot这些经典框架,暂且不表。


本帖子中包含资源

您需要 登录 才可以下载,没有帐号?立即注册

您需要登录后才可以回帖 登录 | 立即注册

2018-2020 ©v2.1 冀ICP备19027484号-2

点击这里给我发消息