目录

1 传统方式处理业务的缺点

2 MVC架构模式理论基础

4 MVC架构模式如何设计

4.1 设计JDBC工具类的封装

4.2 创建封装数据的对象

4.3 设计Dao模式

4.4 业务逻辑编写

4.5 调度中心的编写

4.6 MVC框架和三层架构之间的关系

4.7 解决事务问题


1 传统方式处理业务的缺点

首先创建一个数据库表:

新增两个数据:

代码如下:

package com.itzw.bank.web.servlet;import com.itzw.bank.exceptions.AppException;
import com.itzw.bank.exceptions.MoneyNotEnoughException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;@WebServlet("/tansfer")
public class AccountTransferServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();//获取前端提交的信息String formAct = request.getParameter("formAct");String toAct = request.getParameter("toAct");double money = Double.parseDouble(request.getParameter("money"));//连接数据库//1.转账前判断余额够不够Connection conn = null;PreparedStatement ps = null;PreparedStatement ps2 = null;PreparedStatement ps3 = null;ResultSet rs = null;try {//注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//获取连接String url = "jdbc:mysql://127.0.0.1:3306/mvc";String user = "root";String password = "123456";conn = DriverManager.getConnection(url,user,password);//开启事务(不再自动提交,改为手动提交)conn.setAutoCommit(false);//获取预编译的数据库操作对象String sql1 = "select balance from t_act where actno = ?";ps = conn.prepareStatement(sql1);ps.setString(1,formAct);//执行sqlrs = ps.executeQuery();//处理结果集if (rs.next()){double balance = rs.getDouble("balance");if (balance < money){//余额不足(报余额不足异常)throw new MoneyNotEnoughException("您的余额不足,赶紧充钱!");}//到这余额是够的//给001减10000,//给002加10000String sql2 = "update t_act set balance = balance - ? where actno = ?";ps2 = conn.prepareStatement(sql2);ps2.setDouble(1,money);ps2.setString(2,formAct);int count = ps2.executeUpdate();//手动设置一个异常/* String s = null;s.toString();*/String sql3 = "update t_act set balance = balance + ? where actno = ?";ps3 = conn.prepareStatement(sql3);ps3.setDouble(1,money);ps3.setString(2,toAct);//累计count += ps3.executeUpdate();if (count != 2){throw new AppException("App异常,请联系管理员");}//手动提交事务conn.commit();//转账成功out.print("转账成功!");}} catch (Exception e) {//事务回滚if (conn != null) {try {conn.rollback();} catch (SQLException ex) {ex.printStackTrace();}}//报错提示//e.printStackTrace();out.print(e.getMessage());}finally {if (rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (ps2 != null) {try {ps2.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (ps3 != null) {try {ps3.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}
}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"><title>银行转账</title></head><body><form action="tansfer" method="post">转出账户:<input type="text" name="formAct"><br>转入账户:<input type="text" name="toAct"><br>转账金额:<input type="text" name="money"><br><input type="submit" value="转账"><br></form></body>
</html>

这种银行转账的代码我们之前就写过,首先写一个前端页面,在数据库中创建一个表,然后使用Servlet连接数据库并进行核心业务处理,注意还要手动提交事务,最终完成转账,但我们也发现一个问题,本次转账代码中的Servlet基本上完成了所有任务,比如数据接收、核心业务处理、数据库表中数据的曾删改查、页面数据展示。这就导致这个程序的复用性很低,当我还有别的业务需求的时候,需要再写一遍相同的代码;耦合度高,程序很难扩展;操作数据库的代码和业务逻辑混杂在一起,很容易出错。无法专注业务逻辑的编写。

2 MVC架构模式理论基础

系统为什么要分层?

希望专人干专事,各司其职,职能分工明确,这样可以让代码耦合度降低,扩展能力增强。

软件架构中,有一个非常著名的架构模式:MVC架构模式

  • M(Model:数据/业务) V(View:视图/展示) C(Controller:控制器)
  • C是核心,是控制器,是司令官
  • M处理业务,是处理数据的一个秘书
  • V负责页面的展示的另一个秘书
  • MVC:一个司令官,调度两个秘书去做这件事

实现MVC大致流程:用户发送请求,Controller接收请求,它会把请求发给Model处理,Model连接数据库处理完数据在返回给Controller,拿到数据再发给View展示数据,然后返回给Controller,最终响应到用户。

4 MVC架构模式如何设计

4.1 设计JDBC工具类的封装

package com.itzw.bank.utils;import java.sql.*;
import java.util.ResourceBundle;/*** JDBC工具类的封装* @author zhouzhouzhou* @version 1.0* @since 1.0*/
public class DBUtil {private static ResourceBundle bundle = ResourceBundle.getBundle("resources/jdbc");private static String driver = bundle.getString("driver");private static String url = bundle.getString("url");private static String user = bundle.getString("user");private static String password = bundle.getString("password");//编写私有无参构造是因为不让创建对象,因为工具类中的方法都是静态的,不需要创建对象private DBUtil(){}//在类加载时注册驱动static {try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 获取连接,没有使用数据库连接池* @return connection* @throws SQLException*/public static Connection getConnection() throws SQLException {Connection connection =  DriverManager.getConnection(url, user, password);return connection;}public static void close(Connection conn, Statement ps, ResultSet rs){if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}

4.2 创建封装数据的对象

创建名为Account的类,用它来封装对象,有的人会把这种专门封装数据的对象称之为bean对象,也有人称之为pojo对象,还有人称为domain对象,都一样,称呼不同而已。还需要注意的是属性的类型选择,一般不建议设计为基本数据类型,建议使用包装类,防止null带来问题,就比如我这次的数据类型,它是对象数据库的,数据库中的bigint对应java的long,但是我用Long代替long,还有数据库中的decimal表示java中的double,我用Double代替double:

package com.itzw.bank.mvc;public class Account {//idprivate Long id;//账号private String actno;//余额private Double balance;public Account() {}public Account(Long id, String actno, Double balance) {this.id = id;this.actno = actno;this.balance = balance;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getActno() {return actno;}public void setActno(String actno) {this.actno = actno;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}@Overridepublic String toString() {return "Account{" +"id=" + id +", actno='" + actno + '\'' +", balance=" + balance +'}';}
}

4.3 设计Dao模式

  • 它是JavaEE设计模式之一
  • 创建AccountDao类,它用来负责对Account数据的增删改查
  • 什么是Dao:Data Access Object(数据访问对象)
  • Dao只负责对数据库表的CRUD,没有任何业务逻辑在里面。
  • 一般情况下一张表对应一个Dao
package com.itzw.bank.mvc;import com.itzw.bank.utils.DBUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;public class AccountDao {/*** 插入数据* @param act* @return*/public int insert(Account act){Connection conn = null;PreparedStatement ps = null;int count = 0;try {conn = DBUtil.getConnection();String sql = "insert into t_act (actno,balance) values (?,?)";ps = conn.prepareStatement(sql);ps.setString(1,act.getActno());ps.setDouble(2,act.getBalance());count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(conn,ps,null);}return count;}/*** 根据id删除数据* @param id* @return*/public int deleteById(Long id){Connection conn = null;PreparedStatement ps = null;int count = 0;try {conn = DBUtil.getConnection();String sql = "delete from t_act where id = ?";ps = conn.prepareStatement(sql);ps.setLong(1,id);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(conn,ps,null);}return count;}/*** 修改数据* @param act* @return*/public int update(Account act){Connection conn = null;PreparedStatement ps = null;int count = 0;try {conn = DBUtil.getConnection();String sql = "update t_act set actno = ?,balance = ? where id = ?";ps = conn.prepareStatement(sql);ps.setString(1,act.getActno());ps.setDouble(2,act.getBalance());ps.setLong(3,act.getId());count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(conn,ps,null);}return count;}/*** 根据账户查找数据* @param actno* @return*/public Account selectByActno(String actno){Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;Account act = null;try {conn = DBUtil.getConnection();String sql = "select id,balance from t_act where actno = ?";ps = conn.prepareStatement(sql);ps.setString(1,actno);rs = ps.executeQuery();if (rs.next()){long id = rs.getLong("id");double balance = rs.getDouble("balance");//将结果封装成java对象act = new Account(id,actno,balance);}} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(conn,ps,rs);}return act;}/*** 返回所有数据* @return*/public List<Account> selectAll(){Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;List<Account> list = new ArrayList<>();try {conn = DBUtil.getConnection();String sql = "select id,actno,balance from t_act";ps = conn.prepareStatement(sql);rs = ps.executeQuery();while (rs.next()){long id = rs.getLong("id");String actno = rs.getString("actno");double balance = rs.getDouble("balance");Account act = new Account(id,actno,balance);list.add(act);}} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(conn,ps,rs);}return list;}
}

4.4 业务逻辑编写

package com.itzw.bank.mvc;import com.itzw.bank.exceptions.AppException;
import com.itzw.bank.exceptions.MoneyNotEnoughException;public class AccountService {private AccountDao accountDao = new AccountDao();public void transfer(String fromActno,String toActno,double money) throws MoneyNotEnoughException, AppException {//判断钱够不够Account fromAct = accountDao.selectByActno(fromActno);if (fromAct.getBalance() < money){//余额不足throw new MoneyNotEnoughException("余额不足,感觉充钱吧!");}//余额充足Account toAct = accountDao.selectByActno(toActno);//更改内存中的金额fromAct.setBalance(fromAct.getBalance() - money);toAct.setBalance(toAct.getBalance() + money);//更改数据库中的金额int count = accountDao.update(fromAct);count += accountDao.update(toAct);if (count != 2){throw new AppException("数据库异常,请联系管理员!");}}}

4.5 调度中心的编写

package com.itzw.bank.mvc;import com.itzw.bank.exceptions.AppException;
import com.itzw.bank.exceptions.MoneyNotEnoughException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;/*** 账户小程序,它是一个司令官或者说是Controller* @author zhouzhou* @version 2.0* @since 2.0*/@WebServlet("/tansfer")
public class AccountServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//接收数据String formAct = request.getParameter("formAct");String toAct = request.getParameter("toAct");double money = Double.parseDouble(request.getParameter("money"));//调用业务方法处理AccountService accountService = new AccountService();try {accountService.transfer(formAct,toAct,money);//成功了,展示处理结果response.sendRedirect(request.getContextPath()+"/success.jsp");} catch (MoneyNotEnoughException e) {//失败了(余额不足)response.sendRedirect(request.getContextPath()+"/moneynotenough.jsp");} catch (Exception e) {//失败了response.sendRedirect(request.getContextPath()+"/error.jsp");}}
}

4.6 MVC框架和三层架构之间的关系

三层架构是什么样的呢?

  • 三层架构的三层分别为:表现层(web层/表示层)、业务逻辑层、持久化层
  • 其中表现层中包含的有Servlet、JSP等等;业务逻辑层是service;持久化层是Dao
  • 当用户发送请求的时候,会先发送给表现层,然后表现层发给业务逻辑层,然后业务逻辑层发给持久化层,持久化层再连接数据库,得到数据再原路返回,最终返回到用户。
  • 就像前面我们写的代码一样,Servlet中包含着service,service包含着Dao,而Dao又连接着DB数据库

MVC框架之前我们就讲过:

Controller像总司令一样负责控制Model和View,而其中Model也就是负责处理数据的环节,它包含了业务逻辑层和持久化层,这也很好理解,Model负责业务处理,而业务逻辑层也就是service就是负责业务处理的,而业务处理必然是包含着Dao也就是持久化层的。总司令controller和view就相当于表现层,因为他们是直接与用户接触的。这也MVC框架和三层架构的关系就了然了。

4.7 解决事务问题

我们发现将各种事情分开来做之后,事务就很难写进去,需要改很多东西,而改过之后代码复杂很多,而且失去了原有的专人做专事的特性,改造过程有一点麻烦,懒得改了。。。究其原因,为什么改造麻烦,因为Connection会创建多个,为了不创建多个不得不在多个文件中传入相同的Connection。然后我们发现线程Thread是不会变得,有没有可能存在一个Map集合,它里面的key装着当前的Thread,而value就是Connection,这样我们不需要传入Connection,只需要获取Thread即可。还真有,那就是ThreadLocal集合,可以将Connection对象装入其中,需要放在DBUtil文件中的getConnection中,在Dao文件使用这个工具类时或者其它文件使用这个工具类时拿到的Connection对象都是同一个Connection对象。主要修改getConnection方法即可,如下:

    private static ThreadLocal<Connection> local = new ThreadLocal<>();/*** 获取连接,没有使用数据库连接池* @return connection* @throws SQLException*/public static Connection getConnection() throws SQLException {Connection connection = local.get();if (connection == null){connection =  DriverManager.getConnection(url, user, password);local.set(connection);}return connection;}

注意最后要将conn从Map集合中移除

        if (conn != null) {try {conn.close();//思考,为什么conn关闭之后要从大Map中移除呢//根本原因是:Tomcat服务器是支持线程池的,也就是说一个人用过了t1线程,t1线程还有其它用户使用local.remove();} catch (SQLException e) {e.printStackTrace();}}

至此,这个小项目已经相当完美了!!但还是可以改进,比如目录,给不同任务的文件都新建一个对应的包,如下:

还有一点,一般层与层直接是用接口连接,这样可以降低耦合度,提高扩展力。也就是业务逻辑层和持久化层用接口实现。也就是dao文件和service文件需要使用接口实现,如下:

package com.itzw.bank.dao;import com.itzw.bank.pojo.Account;import java.util.List;public interface AccountDao {int insert(Account act);int deleteById(Long id);int update(Account act);Account selectByActno(String actno);List<Account> selectAll();
}
package com.itzw.bank.service;import com.itzw.bank.exceptions.AppException;
import com.itzw.bank.exceptions.MoneyNotEnoughException;public interface AccountService {public void transfer(String fromActno,String toActno,double money) throws MoneyNotEnoughException, AppException;
}

然后在新建impl包在里面新建类实现对应接口即可,注意实现接口要使用多态了,如下:

    private AccountDao accountDao = new AccountDaoImpl();//多态

到这就差不多结束了,依然有一些问题,不过大致格式就是这样,以后写项目就按这种目录结构编写,非常的规范。

Java学习-MVC架构模式相关推荐

  1. java三层 开源_java 山寨qq 聊天工具(基于mvc三层架构,附 mvc架构模式pdf说明文档)支持开源...

    [实例简介] java 山寨qq 聊天工具(基于mvc三层架构,附 mvc架构模式pdf说明文档)支持开源 [实例截图] [核心代码] java山寨qq聊天工具(基于mvc三层架构,附mvc架构模式p ...

  2. MyBatis学习:简单认识一下MVC架构模式和三层架构

    1.本篇博客的背景和目的 目前我本人正在学习MyBatis框架,在原先了解并且懵懵懂懂使用的基础上,开始系统正式的学习.本篇博客阐述一下MVC架构模式和三层架构,以及明晰一下我们通常在Web项目中的编 ...

  3. java 学习写架构必会几大技术点

    java 学习写架构必会几大技术点 关于学习架构,必须会的几点技术  1. java反射技术  2. xml文件处理  3. properties属性文件处理  4. 线程安全机制  5. annoc ...

  4. data spring 指定时区_Spring 框架基础(05):Mvc架构模式,执行流程详解

    本文源码:GitHub || GitEE 一.SpringMvc框架简介 1.Mvc设计理念 MVC是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个组件里面, ...

  5. spring mvc返回页面显示空白_Spring 框架基础(06):Mvc架构模式简介,执行流程详解...

    一.SpringMvc框架简介 1.Mvc设计理念 MVC是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个组件里面,在改进和个性化定制界面及用户交互的同时,不 ...

  6. Spring 框架基础(06):Mvc架构模式简介,执行流程详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.SpringMvc框架简介 1.Mvc设计理念 MVC是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集 ...

  7. .net mvc actionresult 返回字符串_Spring 框架基础(06):Mvc架构模式简介,执行流程详解

    一.SpringMvc框架简介 1.Mvc设计理念 MVC是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个组件里面,在改进和个性化定制界面及用户交互的同时,不 ...

  8. 理解MVC架构模式,SpringMVC原理、执行流程图解

    1.MVC架构模式 说起SpringMVC就不得不说MVC,MVC是一种经典架构模式.MVC架构模式的重点是为了解耦,将软件用户界面和业务逻辑分离以使代码可扩展性.可复用性.可维护性.灵活性加强,很多 ...

  9. Android 架构之 MVC 架构模式

    前言 由于 MVP.MVVM.组件化架构的兴起,MVC 架构在 android 中的应用变得越来越少,但 MVC 是基础,理解好 MVC 才能更好的理解 MVP,MVVM,因为后两种都是基于 MVC ...

最新文章

  1. 2018-3-6 (论文—网络评论中非结构信息应用于研究)笔记-----论文中的特征抽取的模型算法
  2. 让你的博士经历更加轻松愉快的10个tips
  3. centos7 安装apache+php+memcache
  4. Bzoj4558 [JLoi2016]方
  5. 修复“-bash: locate: command not found”
  6. clientHeight , scrollHeight , offsetHeight之间的区别及兼容方案
  7. SQL Server 分区表的创建方法与管理
  8. 深圳6月23号活动《产品经理三分钟》报名开始啦!
  9. Makefile 自动产生依赖
  10. OO实现ALV TABLE 九:ALV的事件
  11. ZooKeeper动态重新配置
  12. sqlmap地表最强sql注入检测工具学习使用
  13. 分层结构的生活例子_详解软件分层架构设计、工作原理、实例以及具体架构
  14. linux下关于程序性能和系统性能的工具、方法
  15. 【图像去噪】基于matlab维纳滤波图像去噪【含Matlab源码 725期】
  16. socket 支持 ipv6
  17. SecureCRT无法使用Zmodem上传下载文件
  18. Android APK安装后资源文件(res/assets)位置
  19. 安装程序无法自动安装Virtual Machine Communication Interface Sockets(VSock)驱动程序
  20. 倒看北斗星---念霍去病

热门文章

  1. 【计算机组成原理】门阵列译码器
  2. Flash新手教程:打造拟真生态水族鱼缸-添加动画效果
  3. 瑞幸点燃导火索,兄弟公司神州租车迎大变局
  4. Typora+阿里云OSS(将图片上传到阿里云服务器上)
  5. android x86小白安装教程,电脑上安装Android 10小白教程,大屏Android用起来
  6. 最伟大的软件Unix---英雄迟暮
  7. 信息安全专家李钊博士:信息物理系统概述
  8. 逆元 与等比数列求和
  9. 万卷书- 创新型学校 [Creative Schools]
  10. kubernetes搭建rook-ceph