MVC架构模式学习笔记(动力节点老杜2022)

GitHub代码笔记:laodu-mvc: 动力节点学习javaweb中的mvc笔记。

文章目录

1.视频链接
2.不使用MVC架构模式程序存在的缺陷
3.MVC架构模式理论基础
4.JavaEE设计模式-DAO模式
5.pojo & bean & domain
6.业务层抽取以及业务类实现
7.控制层
8.MVC架构模式与三层架构的关系
9.手撕ThreadLocal源码
10.ThreadLocal的使用
11.不同功能的类放在不同的包下
12.层与层之间应该使用接口进行衔接以及当前项目存在的两大问题

 1 视频链接

JavaWeb课程导读_哔哩哔哩_bilibili


2 不使用MVC架构模式程序存在的缺陷

  • 在不使用MVC架构模式的前提下,完成银行账户转账。
  • 分析以下AccountTransferServlet他都负责了什么?
    • 1> 负责了数据接收
    • 2> 负责了核心的业务处理
    • 3> 负责了数据库表中数据的CRUD操作(Create【增】 Retrieve【查】 Update【改】 Delete【删】)
    • 4> 负责了页面的数据展示
  • 分析这个程序存在哪些问题?
    • 缺点1> 代码的复用性太差。(代码的重用性太差)
      • 导致缺点1的原因?
      • 因为没有进行“职能分工”,没有独立组件的概念,所以没有办法进行代码复用。代码和代码之间的耦合度太高,扩展力太差。
    • 缺点2> 耦合度高,导致了代码很难扩展。
    • 缺点3> 操作数据库的代码和业务逻辑混杂在一起,很容易出错。编写代码的时候很容易出错,无法专注业务逻辑的编写。

3 MVC架构模式理论基础


4 JavaEE设计模式-DAO模式

  • AccountDao是负责Account数据的增删改查的。
  • 什么是DAO?
    • Data Access Object(数据访问对象)
  • DAO实际上是一种设计模式,属于JavaEE的设计模式之一。(不是23种设计模式。)
  • DAO只负责数据库表的CRUD,没有任何业务逻辑在里面。
  • 没有任何业务逻辑,只负责表中数据增删改查的对象,有一个特殊的称谓:DAO对象。
  • 为什么叫做AccountDao呢?
    • 这是因为这个DAO是专门处理t_act这张表的。
    • 如果处理t_user表的话,可以叫做:UserDao
    • 如果处理t_student表的话,可以叫做:StudentDao
  • 一般情况下:一张表会对应一个DAO对象(pojo / bean / domain)。
  • DAO中的方法名很固定了,一般都是:
    • insert
    • deleteByXxx
    • update
    • selectByXxx
    • selectAll

5 pojo & bean & domain

  • 账户实体类:封装账户信息的。
  • 一般是一张表对应一个。
  • 这种普通简单的对象被成为pojo对象。
  • 有的人也会把这种专门封装数据的对象,称为bean对象。(javabean:咖啡豆)
  • 有的人也会把这种专门封装数据的对象,称为领域模型对象。domain对象。
  • 不同的程序员有不同的习惯。
public class Account { // 这种普通简单的对象被成为pojo对象。/*** 主键*/// 一般这种属性不建议设计为基本数据类型,建议使用包装类。防止null带来的问题。//private long id;private Long id;/*** 账号*/private String actno;/*** 余额*///private double balance;private Double balance;@Overridepublic String toString() {return "Account{" +"id=" + id +", actno='" + actno + '\'' +", 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;}public Account(Long id, String actno, Double balance) {this.id = id;this.actno = actno;this.balance = balance;}public Account() {}
}

6 业务层抽取以及业务类实现

  • service翻译为:业务。
  • AccountService:专门处理Account业务的一个类。
  • 在该类中应该编写纯业务代码。(只专注业务。不写别的。不和其他代码混合在一块。)
  • 只希望专注业务,能够将业务完美实现,少量bug。
  • 业务类一般起名:XxxService、XxxBiz…
public class AccountService {// 为什么定义到这里?因为在每一个业务方法中都可以需要连接数据库。private AccountDao accountDao = new AccountDao();// 这里的方法起名,一定要体现出,你要处理的是什么业务。// 我们要提供一个能够实现转账的业务方法(一个业务对应一个方法。)/*** 完成转账的业务逻辑* @param fromActno 转出账号* @param toActno 转入账号* @param money 转账金额*/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);// 修改余额(只是修改了内存中java对象的余额)fromAct.setBalance(fromAct.getBalance() - money);toAct.setBalance(toAct.getBalance() + money);// 更新数据库中的余额int count = accountDao.update(fromAct);// 模拟异常String s = null;s.toString();count += accountDao.update(toAct);if (count != 2) {throw new AppException("账户转账异常!!!");}}}

7 控制层

  • 账户小程序
  • AccountServlet是一个司令官。他负责调度其他组件来完成任务。
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet { // AccountServlet作为Controllerprivate AccountService accountService = new AccountService();@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 接收数据String fromActno = request.getParameter("fromActno");String toActno = request.getParameter("toActno");double money = Double.parseDouble(request.getParameter("money"));try {// 调用业务方法处理业务(调度Model处理业务)accountService.transfer(fromActno, toActno, money);// 执行到这里了,说明成功了。// 展示处理结果(调度View做页面展示)response.sendRedirect(request.getContextPath() + "/success.jsp");} catch(MoneyNotEnoughException e) {// 执行到这里了,说明失败了。(余额不足)// 展示处理结果(调度View做页面展示)response.sendRedirect(request.getContextPath() + "/moneynotenough.jsp");} catch(Exception e){// 执行到这里了,说明失败了。response.sendRedirect(request.getContextPath() + "/error.jsp");}}
}

8 MVC架构模式与三层架构的关系


9 手撕ThreadLocal源码

public class Connection {
}
public class DBUtil {// 静态变量特点:类加载时执行,并且只执行一次。// 全局的大Map集合private static MyThreadLocal<Connection> local = new MyThreadLocal<>();/*** 每一次都调用这个方法来获取Connection对象* @return*/public static Connection getConnection(){Connection connection = local.get();if (connection == null) {// 第一次调用:getConnection()方法的时候,connection一定是空的。// 空的就new一次。connection = new Connection();// 将new的Connection对象绑定到大Map集合中。local.set(connection);}return connection;}}
package com.ycy.threadlocal;import java.util.HashMap;
import java.util.Map;/*** 自定义一个ThreadLocal类*/
public class MyThreadLocal<T> {/*** 所有需要和当前线程绑定的数据要放到这个容器当中*/private Map<Thread, T> map = new HashMap<>();/*** 向ThreadLocal中绑定数据*/public void set(T obj){map.put(Thread.currentThread(), obj);}/*** 从ThreadLocal中获取数据* @return*/public T get(){return map.get(Thread.currentThread());}/*** 移除ThreadLocal当中的数据*/public void remove(){map.remove(Thread.currentThread());}
}
package com.ycy.threadlocal;
// 张三发送请求,对应一个线程t1
// 李四发送请求,对应一个线程t2
public class Test {public static void main(String[] args) {Thread thread = Thread.currentThread();System.out.println(thread);// 调用serviceUserService userService = new UserService();userService.save();}
}
package com.ycy.threadlocal;public class UserService {private UserDao userDao = new UserDao();public void save(){Thread thread = Thread.currentThread();System.out.println(thread);Connection connection = DBUtil.getConnection();System.out.println(connection);userDao.insert();}}
package com.ycy.threadlocal;public class UserDao {public void insert(){Thread thread = Thread.currentThread();System.out.println(thread);Connection connection = DBUtil.getConnection();System.out.println(connection);System.out.println("User DAO insert");}
}


10 ThreadLocal的使用

JDK有ThreadLocal类的实现

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(){}// DBUtil类加载时注册驱动static {try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}// 这个对象实际上在服务器中只有一个。private static ThreadLocal<Connection> local = new ThreadLocal<>();/*** 这里没有使用数据库连接池,直接创建连接对象。* @return 连接对象* @throws SQLException*/public static Connection getConnection() throws SQLException {Connection conn = local.get();if (conn == null) {conn = DriverManager.getConnection(url, user, password);local.set(conn);}return conn;}/*** 关闭资源* @param conn 连接对象* @param stmt 数据库操作对象* @param rs 结果集对象*/public static void close(Connection conn, Statement stmt, ResultSet rs){if (rs != null) {try {rs.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (stmt != null) {try {stmt.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (conn != null) {try {conn.close();// 思考一下:为什么conn关闭之后,这里要从大Map中移除呢?// 根本原因是:Tomcat服务器是支持线程池的。也就是说一个人用过了t1线程,t1线程还有可能被其他用户使用。local.remove();} catch (SQLException e) {throw new RuntimeException(e);}}}}
public class AccountService {// 为什么定义到这里?因为在每一个业务方法中都可以需要连接数据库。private AccountDao accountDao = new AccountDao();// 这里的方法起名,一定要体现出,你要处理的是什么业务。// 我们要提供一个能够实现转账的业务方法(一个业务对应一个方法。)/*** 完成转账的业务逻辑* @param fromActno 转出账号* @param toActno 转入账号* @param money 转账金额*/public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {// service层控制事务try (Connection connection = DBUtil.getConnection()){System.out.println(connection);// 开启事务(需要使用Connection对象)connection.setAutoCommit(false);// 查询余额是否充足Account fromAct = accountDao.selectByActno(fromActno);if (fromAct.getBalance() < money) {throw new MoneyNotEnoughException("对不起,余额不足");}// 程序到这里说明余额充足Account toAct = accountDao.selectByActno(toActno);// 修改余额(只是修改了内存中java对象的余额)fromAct.setBalance(fromAct.getBalance() - money);toAct.setBalance(toAct.getBalance() + money);// 更新数据库中的余额int count = accountDao.update(fromAct);// 模拟异常String s = null;s.toString();count += accountDao.update(toAct);if (count != 2) {throw new AppException("账户转账异常!!!");}// 提交事务connection.commit();} catch (SQLException e) {throw new AppException("账户转账异常!!!");}}}
public class AccountDao {/*** 插入账户信息* @param act  账户信息* @return 1表示插入成功*/public int insert(Account act) {PreparedStatement ps = null;int count = 0;try {Connection 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) {throw new RuntimeException(e);} finally {DBUtil.close(null, ps, null);}return count;}/*** 根据主键删除账户* @param id 主键* @return*/public int deleteById(Long id){PreparedStatement ps = null;int count = 0;try {Connection 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) {throw new RuntimeException(e);} finally {DBUtil.close(null, ps, null);}return count;}/*** 更新账户* @param act* @return*/public int update(Account act) {PreparedStatement ps = null;int count = 0;try {Connection conn = DBUtil.getConnection();System.out.println(conn);String sql = "update t_act set balance = ? , actno = ? where id = ?";ps = conn.prepareStatement(sql);ps.setDouble(1, act.getBalance());ps.setString(2, act.getActno());ps.setLong(3, act.getId());count = ps.executeUpdate();} catch (SQLException e) {throw new RuntimeException(e);} finally {DBUtil.close(null, ps, null);}return count;}/*** 根据账号查询账户* @param actno* @return*/public Account selectByActno(String actno){PreparedStatement ps = null;ResultSet rs = null;Account act = null;try {Connection conn = DBUtil.getConnection();System.out.println(conn);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();act.setId(id);act.setActno(actno);act.setBalance(balance);}} catch (SQLException e) {throw new RuntimeException(e);} finally {DBUtil.close(null, ps, rs);}return act;}/*** 获取所有的账户* @return*/public List<Account> selectAll() {PreparedStatement ps = null;ResultSet rs = null;List<Account> list = new ArrayList<>();try {Connection 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 account = new Account();account.setId(id);account.setActno(actno);account.setBalance(balance);*/Account account = new Account(id, actno, balance);// 加到List集合list.add(account);}} catch (SQLException e) {throw new RuntimeException(e);} finally {DBUtil.close(null, ps, rs);}return list;}}

11 不同功能的类放在不同的包下

ssm里面一般都把dao包起名为mapper,把web包起名为controller

12 层与层之间应该使用接口进行衔接以及当前项目存在的两大问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/744141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch之Nested对象

写在前面 本文看下es的nested嵌套对象相关内容。 1&#xff1a;es用了啥范式&#xff1f; 在关系型数据库中定义了6大数据库范式,即1&#xff0c;2&#xff0c;3&#xff0c;BC&#xff0c;4&#xff0c;5的NF&#xff08;normal form&#xff09;,分别如下&#xff1a; 1N…

学习编程为什么选择C/C++,那么C++的强大之处到底体现在哪里呢?

学习编程为什么选择C/C&#xff0c;那么C的强大之处到底体现在哪里呢&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共…

ctf_show笔记篇(web入门---代码审计)

301&#xff1a;多种方式进入 从index.php页面来看 只需要访问index.php时session[login]不为空就能访问 那么就在访问index.php的时候上传login 随机一个东西就能进去从checklogin页面来看sql注入没有任何过滤 直接联合绕过 密码随意 还有多种方式可以自己去看代码分析 30…

力扣串题:字符串中的第二大数字

此题的精妙之处在于char类型到int类型的转化&#xff0c;需要运算来解决 int secondHighest(char * s) {int max1-1;int max2-1;int szstrlen(s);int i 0 ;for(i0;i<sz;i){if(s[i]>0&&s[i]<9){if((s[i]-0)>max1){max2max1;max1s[i]-0;}else if((s[i]-0)&l…

峟思仪器助力尾矿库安全监测

在矿业领域&#xff0c;尾矿库的安全监测是保障矿山持续、安全运营的关键环节。尾矿库通常用于存放矿山开采过程中产生的固体废物&#xff0c;如果管理不善&#xff0c;可能会造成重大的安全事故&#xff0c;对环境和人类健康造成严重威胁。因此&#xff0c;采用先进的监测技术…

Sqllab第一关通关笔记

知识点&#xff1a; 明白数值注入和字符注入的区别 数值注入&#xff1a;通过数字运算判断&#xff0c;1/0 1/1 字符注入&#xff1a;通过引号进行判断&#xff0c;奇数个和偶数个单引号进行识别 联合查询&#xff1a;union 或者 union all 需要满足字段数一致&…

机界先锋:Figure 01实现全面沟通与AGI通用人工智能的征途

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

yum安装mysql 数据库tab自动补全

centos7上面没有mysql&#xff0c;它的数据库名字叫做mariadb [rootlocalhost ~]#yum install mariadb-server -y [rootlocalhost ~]#systemctl start mariadb.service [rootlocalhost ~]#systemctl stop firewalld [rootlocalhost ~]#setenforce 0 [rootlocalhost ~]#ss -na…

2024年大学生买腾讯云_腾讯云大学生服务器优惠

腾讯云学生服务器优惠活动「云校园」轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年&#xff0c;轻量应用服务器4核8G配置112元3个月、352.8元6个月、646.8元一年&#xff0c;CVM云服务器2核4G3M公网带宽配置842.4元一年&#xff0c;腾讯云服务器网txyfwq.com分享2…

H12-811_128

128.如下图所示的网络&#xff0c;两台交换机之间通过四条链路相连&#xff0c;COPPER指电接口&#xff0c;FIBR指光接口&#xff0c;则以下哪两个接口可以实现链路聚合? A.G0/0/3和FE0/0/3 B.G0/0/3和G0/0/2 C.G0/0/2和FE0/0/3 D.G0/0/2和G0/0/1 答案&#xff1a;BD 注释&am…

Mysql 死锁案例2-间隙锁与意向插入锁冲突

死锁复现 CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB DEFAULT CHARSETutf8;/*Data for the table t */insert into t(id,c,d) values (0,0,0),(5,5,5),(10,10,10) 事务1事务2T1START …

英语同传翻译,北京本地同声传译收费价格多少

同声传译是一项高度专业化的服务&#xff0c;广泛应用于国际会议、商务洽谈、法庭审判等场合。由于其对译员的语言能力、专业知识以及应变能力的极高要求&#xff0c;使得同声传译的收费价格也相对较高。那么&#xff0c;英语同传翻译北京本地同声传译的收费价格到底是多少呢&a…

Likeshop多商户高级商城系统已上线,支持DIY页面设计,打造个性化商城!

Likeshop多商户高级商城系统来啦&#xff01;这是一款功能强大、灵活多样的电商平台解决方案&#xff0c;旨在为企业提供一站式的多渠道商城搭建服务。该系统支持多种经营模式&#xff0c;包括平台自营、联营、招商等&#xff0c;为企业提供了丰富的运营选择。无论运营还是二开…

【原创】浅谈银行票据ABS的几种模式

前 言 2017年6月20日&#xff0c;中国票据网宣布下线&#xff0c;这位承载着无数票据人回忆的老朋友虽然离开了大家&#xff0c;但是**以票据类资产作为基础资产在沪深证券交易所发行的资产支持证券&#xff08;以下简称“票据ABS”&#xff09;**却方兴未艾&#xff0c;自201…

Ajax(2)

图片上传 传图片文件不能像传文字一样用JSON格式&#xff0c;可以用form-data类型携带文件 1.获取图片文件对象 2.使用FormData&#xff08;浏览器内置的构造函数&#xff09;携带图片文件 3.提交表单数据到服务器&#xff0c;返回图片网址 这里可能用到的事件监听器&#…

低功耗漏电保护电路芯片D54123B介绍

概 述 A&#xff09;、D54123B是一款高性能 CMOS 漏电保护器专用电路。芯片内部包含稳压电源、放大电路、比较器电路、延时电路、计数器电路、跳闸控制电路及跳闸驱动电路。芯片外围应用有脱扣线圈、压敏电阻、稳压二级管、二级管、电阻、电容等元器件。 B&#xff09;、内部…

权限管理系统-0.4.1

5.4 权限管理前端开发 5.4.1 src/components 新建ParentView文件夹&#xff0c;并在文件夹中新建index.vue文件。 并在index.vue中加入以下内容&#xff1a; <template><router-view /> </template>5.4.2 layout/components/Sidebar/index.vue routes() …

金蝶云星空对接打通阿里宜搭逐个单据查询接口与新增表单实例接口

金蝶云星空对接打通阿里宜搭逐个单据查询接口与新增表单实例接口 数据源平台:金蝶云星空 金蝶K/3Cloud结合当今先进管理理论和数十万家国内客户最佳应用实践&#xff0c;面向事业部制、多地点、多工厂等运营协同与管控型企业及集团公司&#xff0c;提供一个通用的ERP服务平台。…

网络编程:网络编程基础

一、网络发展 1.TCP/IP两个协议阶段 TCP/IP协议已分成了两个不同的协议&#xff1a; 用来检测网络传输中差错的传输控制协议TCP 专门负责对不同网络进行2互联的互联网协议IP 2.网络体系结构 OSI体系口诀&#xff1a;物链网输会示用 2.1网络体系结构概念 每一层都有自己独…

邮件营销案例分析:哪些因素决定营销效果?

邮件营销案例的关键要素&#xff1f;电子邮件营销案例有哪些&#xff1f; 邮件营销一直是一种重要的推广手段。然而&#xff0c;邮件营销的效果并非一蹴而就&#xff0c;它需要多方面的因素共同作用。AokSend将通过一系列邮件营销案例的分析&#xff0c;探讨哪些因素决定了邮件…