MVC模式分层练习

news2025/2/1 1:47:26

新建库

新建表

插入点数据

先不用MVC模式写功能,来看下缺点是什么

新建一个空项目

选项项目使用的JDK

自己的IDEA总是要重启下

新建模块

因maven还没教

添加框架支持

添加后项目多了这些

添加些必要依赖  这里注意下,如果导入jar包不对可以重新导入下或者是jar包本身出了问题

添加页面

配置Tomcat

启动

请求地址  因现在没有后端

现在写后端 并测试

解决控制台输出乱码问题

System.out输出乱码

需要用到JDBC连接Mysql数据库

导入Mysql驱动jar包

java web项目  一般会在WEB-INF下有个lib用来放Tomcat内没有,外部引入的依赖

可以创建个lib目录  然后将jar包复制进来

具体代码

package com.bank.web;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;

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 java.io.*;
import java.sql.*;
import java.util.Locale;

/**
 * 在不使用MVC架构模式的前提下,完成银行账户转账
 * 分析这个程序存在哪些问题?
 * @author hrui
 * @date 2023/8/31 23:06
 */
@WebServlet("/transfer")
public class AccountTransferServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取响应流对象
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        //获取前端传来的参数
        String fromActno = req.getParameter("fromActno");
        String toActno = req.getParameter("toActno");
        double money = Double.parseDouble(req.getParameter("money"));
//        System.out.println("转出账户:"+fromActno);
//        System.out.println("转入账户:"+fromActno);
//        System.out.println("转账金额:"+fromActno);


        //编写转账的业务逻辑代码,连接数据库,进行转账操作
        //1.转账之前要判断转出账户的余额是否充足

        Connection conn=null;
        PreparedStatement ps=null;
        //PreparedStatement ps2=null;
        ResultSet rs=null;

        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取连接
            conn = DriverManager.getConnection("xxx", "xxx", "xxx");
            conn.setAutoCommit(false);
            //获取执行对象
            String sql="select balance from t_act where actno=?";
            ps = conn.prepareStatement(sql);

            ps.setString(1, fromActno);
            //执行sql,返回结果集
            rs = ps.executeQuery();
            //获取结果集
            if(rs.next()){
                double balance = rs.getDouble("balance");
                if(balance<money){
                    //余额不足(使用异常处理机制)
                    throw new MoneyNotEnoughException("余额不足");
                }
                //程序能到这里,说明余额重组  不需要else
                //开始转账
                sql="update t_act set balance=balance-? where actno=?";
                ps = conn.prepareStatement(sql);
                ps.setDouble(1, money);
                ps.setString(2, fromActno);
                int count = ps.executeUpdate();

                //模拟异常
                String str=null;
                str.toString();

                sql="update t_act set balance=balance+? where actno=?";
                ps=conn.prepareStatement(sql);
                ps.setDouble(1, money);
                ps.setString(2, toActno);
                //累计
                count += ps.executeUpdate();
                if(count!=2){
                    throw new AppException("app异常,请联系管理员");
                }
            }
            conn.commit();
            writer.print("转账成功");
        } catch (ClassNotFoundException | SQLException | MoneyNotEnoughException | AppException e) {
            try {
                if(conn!=null) {
                    conn.rollback();
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
            writer.print(e.getMessage());
        }finally {
            //释放资源,根据JDBC规范 从小到大
            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();
                }
            }
        }
    }
}

1>负责了数据接收

2>负责了核心业务处理

3>负责了数据库表中的CRUD操作(Create(增) Retrieve(查) Update(改) Delete(删))

4>负责了数据的页面展示

引起的缺点:

代码复用性差  比如查余额,可以抽取出来,单独放到一个方法

代码复用性差的原因,没有职能分工,独立组件的概念,代码之间耦合度高,扩展力差

操作数据库代码和业务逻辑混杂在一起,容易出错,无法专注于业务逻辑书写

下面以MVC的模式对上面代码改进

1.系统为什么要分层?

        希望专人干专事.各司其职.分工明确.这样可以降低耦合,扩展增强.复用增强

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

M(Model:数据/业务)       V(View:视图/展示)       C(Controller:控制器/核心)

首先是对JDBC的封装

JDBC工具类

package com.bank.utils;

import java.sql.*;
import java.util.ResourceBundle;

/**
 * @author hrui
 * @date 2023/9/1 10:24
 */
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 username=bundle.getString("username");

    private static String password=bundle.getString("password");

    //不让创建对象,原因工具类方法一般都静态的,无需外部创建对象
    //为防止外部创建对象,构造私有化
    private DBUtil(){

    }

    //DBUtil类加载时注册驱动
    static{
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //没有使用连接池,直接创建的连接对象
    public static Connection getConnection() throws SQLException {
        Connection conn= DriverManager.getConnection(url,username,password);
        return conn;
    }

    public static void close(Connection conn, Statement statement, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

测试连接

封装实体类

package com.bank.mvc;

import java.util.Objects;

/**
 * 账户实体类,用于封装账户信息
 * POJO对象
 * 有的人也会把这种专门封装数据的对象,称为bean对象(javabean:咖啡豆)
 * 有的人也会把这种专门分装数据的对象,称为领域模型对象.domain对象.
 * pojo,bean,domain
 * @author hrui
 * @date 2023/9/1 15:34
 */
public class Account {

    private 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;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Account acount = (Account) o;
        return id.equals(acount.id) && actno.equals(acount.actno) && balance.equals(acount.balance);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, actno, balance);
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
}

编写DAO层

package com.bank.mvc;

import com.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;

/**
 * 负责Acount数据的增删改查
 * 1.什么是DAO
 *      Data Access Object(数据访问对象)
 * 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)
 * 3.DAO只负责数据库CRUD,没有任何业务逻辑
 * 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象
 * @author hrui
 * @date 2023/9/1 12:39
 */
public class AccountDao {

    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();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return count;
    }

    public int deleteByActno(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();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return count;
    }

    public int update(Account act){
        Connection conn=null;
        PreparedStatement ps=null;
        int count=0;
        try {
            conn=DBUtil.getConnection();
            String sql="update t_act set balance=? where id=?";
            ps=conn.prepareStatement(sql);
            ps.setDouble(1, act.getBalance());
            ps.setLong(2, act.getId());
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return count;
    }

    public Account selectBtActNo(String actno){
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Account account=new Account();
        try {
            conn=DBUtil.getConnection();
            String sql="select id,actno,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");
                String actno1=rs.getString("actno");
                Double balance=rs.getDouble("balance");
                account.setId(id);
                account.setActno(actno1);
                account.setBalance(balance);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }

        return account;
    }

    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 account=new Account();
                account.setId(id);
                account.setActno(actno);
                account.setBalance(balance);
                list.add(account);
            }
        } catch (SQLException e) {

            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(conn,ps,null);
        }
        return list;
    }
}

原先在Servlet里

1>负责了数据接收

2>负责了狠心业务处理

3>负责了数据库表中数据CRUD操作

4>负责了页面数据展示

现在已经一层层分离了

两个异常类

用AccountSAervice来做业务处理

具体业务处理代码

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;

/**
 * Service:业务
 * 专门处理Account的业务处理类
 * 该类只专注业务处理
 * 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以
 * @author hrui
 * @date 2023/9/2 0:49
 */
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 fromAccount = accountDao.selectBtActNo(fromActno);
        if(fromAccount.getBalance()<money){
            throw new MoneyNotEnoughException("余额不足");
        }
        //程序到这里说明余额够
        Account toAct=accountDao.selectBtActNo(toActno);

        //修改余额
        fromAccount.setBalance(fromAccount.getBalance()-money);
        toAct.setBalance(toAct.getBalance()+money);

        //更新数据库
        int count=accountDao.update(fromAccount);

        count += accountDao.update(toAct);
        //count++;
        if(count!=2){
            throw new AppException("转账异常");
        }

    }


}

servlet里做的就是调度

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;

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 java.io.IOException;
import java.io.PrintWriter;

/**
 * 让AcountServlet做为Controller  调度员
 * 负责调度其他组件
 * @author hrui
 * @date 2023/9/1 12:27
 */
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取前端传来的参数
        String fromActno = req.getParameter("fromActno");
        String toActno = req.getParameter("toActno");
        double money = Double.parseDouble(req.getParameter("money"));

        //调用业务方法处理业务(调度Model处理业务)
        AccountService accountService=new AccountService();
        try {
            accountService.transfer(fromActno,toActno,money);
            resp.sendRedirect(req.getContextPath()+"/success.jsp");
        } catch (MoneyNotEnoughException e) {
            e.printStackTrace();
            resp.sendRedirect(req.getContextPath()+"/moneynoenough.jsp");
        } catch (AppException e) {
            e.printStackTrace();
            resp.sendRedirect(req.getContextPath()+"/error.jsp");
        }

    }
}

三个页面显示

 

上面代码缺少事务控制,一般事务都在service进行控制

一般来说是在service层去开启事务  提交事务

这里事务管理,做的low的方式就是在业务层获取数据库连接对象,然后传进去,当然这样做的话,在DAO层就不要在finally中关闭事务了.传个null就行,在Service中开启事务,并在Service中提交事务,在Service中的finally中关闭连接

上代码

DAO

package com.bank.mvc;

import com.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;

/**
 * 负责Acount数据的增删改查
 * 1.什么是DAO
 *      Data Access Object(数据访问对象)
 * 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)
 * 3.DAO只负责数据库CRUD,没有任何业务逻辑
 * 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象
 * @author hrui
 * @date 2023/9/1 12:39
 */
public class AccountDao {

    public int insert(Account act,Connection conn){

        PreparedStatement ps=null;
        int count=0;
        try {

            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();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int deleteByActno(Long id,Connection conn){

       PreparedStatement ps=null;
       int count=0;
        try {

            String sql="delete from t_act where id=?";
            ps=conn.prepareStatement(sql);
            ps.setLong(1, id);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int update(Account act,Connection conn){

        PreparedStatement ps=null;
        int count=0;
        try {

            String sql="update t_act set balance=? where id=?";
            ps=conn.prepareStatement(sql);
            ps.setDouble(1, act.getBalance());
            ps.setLong(2, act.getId());
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public Account selectBtActNo(String actno,Connection conn){

        PreparedStatement ps=null;
        ResultSet rs=null;
        Account account=new Account();
        try {

            String sql="select id,actno,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");
                String actno1=rs.getString("actno");
                Double balance=rs.getDouble("balance");
                account.setId(id);
                account.setActno(actno1);
                account.setBalance(balance);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }

        return account;
    }

    public List<Account> selectAll(Connection conn){
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        List<Account> list=new ArrayList<>();
        try {

            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);
                list.add(account);
            }
        } catch (SQLException e) {

            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return list;
    }
}

Service

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;
import com.bank.utils.DBUtil;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Service:业务
 * 专门处理Account的业务处理类
 * 该类只专注业务处理
 * 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以
 * @author hrui
 * @date 2023/9/2 0:49
 */
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层控制事务
        //开启事务(需要用到Connection对象)
        Connection conn=null;
        try {
           conn = DBUtil.getConnection();
           conn.setAutoCommit(false);
            //查询余额是否充足
            Account fromAccount = accountDao.selectBtActNo(fromActno,conn);
            if(fromAccount.getBalance()<money){
                throw new MoneyNotEnoughException("余额不足");
            }
            //程序到这里说明余额够
            Account toAct=accountDao.selectBtActNo(toActno,conn);

            //修改余额
            fromAccount.setBalance(fromAccount.getBalance()-money);
            toAct.setBalance(toAct.getBalance()+money);

            //更新数据库
            int count=accountDao.update(fromAccount,conn);

            count += accountDao.update(toAct,conn);
//        String str=null;
//        str.toString();
            //或者
            //count++;  会向用户提示转账失败  但是转账确已经完成   或者1账户减款而2账户没有加的情况
            if(count!=2){
                throw new AppException("转账异常");
            }
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,null,null);
        }


    }


}

 

但上面代码有点low

如何解决Connection传参问题

用ThreadLocal

改造代码

DBUtil

package com.bank.utils;

import java.sql.*;
import java.util.ResourceBundle;

/**
 * @author hrui
 * @date 2023/9/1 10:24
 */
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 username=bundle.getString("username");

    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<>();

    //没有使用连接池,直接创建的连接对象
    public static Connection getConnection() throws SQLException {
        Connection conn=local.get();
        if(conn==null) {
            conn = DriverManager.getConnection(url, username, password);
            local.set(conn);
        }
        return conn;
    }



    public static void close(Connection conn, Statement statement, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
                //注意:关闭连接时候移除  Tomcat是支持线程池的,不从当前线程里移除 有可能下次别人拿到了,但是conn已经关闭
                local.remove();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

将AccountDao恢复原状,还是从DBUtil里取Connection,但是不需要再传参数,注意finally里面Connection照样传null,原因:还是需要在Service层进行事务控制

package com.bank.mvc;

import com.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;

/**
 * 负责Acount数据的增删改查
 * 1.什么是DAO
 *      Data Access Object(数据访问对象)
 * 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)
 * 3.DAO只负责数据库CRUD,没有任何业务逻辑
 * 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象
 * @author hrui
 * @date 2023/9/1 12:39
 */
public class AccountDao {

    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) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int deleteByActno(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) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public int update(Account act){
        PreparedStatement ps=null;
        int count=0;
        try {
           Connection conn=DBUtil.getConnection();
            String sql="update t_act set balance=? where id=?";
            ps=conn.prepareStatement(sql);
            ps.setDouble(1, act.getBalance());
            ps.setLong(2, act.getId());
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    public Account selectBtActNo(String actno){
        PreparedStatement ps=null;
        ResultSet rs=null;
        Account account=new Account();
        try {
           Connection conn=DBUtil.getConnection();
            String sql="select id,actno,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");
                String actno1=rs.getString("actno");
                Double balance=rs.getDouble("balance");
                account.setId(id);
                account.setActno(actno1);
                account.setBalance(balance);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }

        return account;
    }

    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);
                list.add(account);
            }
        } catch (SQLException e) {

            e.printStackTrace();
            throw new RuntimeException(e);
        }finally {
            DBUtil.close(null,ps,null);
        }
        return list;
    }
}

业务层

package com.bank.mvc;

import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;
import com.bank.utils.DBUtil;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Service:业务
 * 专门处理Account的业务处理类
 * 该类只专注业务处理
 * 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以
 * @author hrui
 * @date 2023/9/2 0:49
 */
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 {
        try(Connection conn= DBUtil.getConnection()){
            conn.setAutoCommit(false);
            //查询余额是否充足
            Account fromAccount = accountDao.selectBtActNo(fromActno);
            if(fromAccount.getBalance()<money){
                throw new MoneyNotEnoughException("余额不足");
            }
            //程序到这里说明余额够
            Account toAct=accountDao.selectBtActNo(toActno);

            //修改余额
            fromAccount.setBalance(fromAccount.getBalance()-money);
            toAct.setBalance(toAct.getBalance()+money);

            //更新数据库
            int count=accountDao.update(fromAccount);

            count += accountDao.update(toAct);
//        String str=null;
//        str.toString();
            //或者
            //count++;  会向用户提示转账失败  但是转账确已经完成   或者1账户减款而2账户没有加的情况
            if(count!=2){
                throw new AppException("转账异常");
            }
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new AppException("转账异常");
        }


    }


}

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

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

相关文章

设计模式-2--工厂模式(Factory Pattern)

一、 什么是工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种创建对象的接口&#xff0c;但是将对象的实例化过程推迟到子类中。工厂模式允许通过调用一个共同的接口方法来创建不同类型的对象&#xff0c;而无需暴露对…

yolov5 应用整理

yolov5 应用整理 适用于0基础人员与有一定yolov5了解的人员食用. 关于yolov5参考: yolov5 github源码链接 目前参与过yolov5的应用: 平台库x86/arm cpuncnnx86libtorch/pytorchBM1684算能标准库(需要进行模型转换)昇腾cann(ascend api) https://gitee.com/Tencent/ncnn ht…

在windows下安装配置skywalking

1.下载地址 Downloads | Apache SkyWalkinghttp://skywalking.apache.org/downloads/ 2.文件目录说明 将文件解压后&#xff0c;可看到agent和bin目录&#xff1a; Agent&#xff1a;作为探针&#xff0c;安装在服务器端&#xff0c;进行数据采集和上报。 Config&#xff1a…

车联网仿真工具Veins安装指南(基于官方文档)

Veins安装指南 官方文档&#xff1a; tutorial 直接选择最easy的way&#xff1a; 下载一个虚拟机&#xff1a;VMware Workstation Player 下载即可。这个普通版是免费的&#xff0c;pro版正版是要收费的&#xff0c;可以找一些其他的方法下载pro版本&#xff0c;可以同时开…

windows11 利用vmware17 安装rocky9操作系统

下载相关软件和镜像 vmware17 下载 下载页面 Download VMware Workstation Pro ​ rocky8镜像下载 官网链接&#xff1a;Rocky Linux 下载页面 Download Rocky | Rocky Linux 点击Minimal下载 安装rocky9 选择镜像文件&#xff0c;点击下一步 点击下一步 启动虚拟机 选…

锂电池充电电路方案

锂电池充电电路一 原理图如下 都是比较小的&#xff0c;SOT-23-6 封装 此方案的优势是器件可以扩容&#xff0c;也就是可以替换成容量更大的mos管。 锂电池充电电路二 锂电池充电电路三 注意线的粗细。 引脚说明 锂电池电量检测电路 键盘上的电量检测电路原理图 电量检…

3D视觉测量:形位公差 平面度测量(附源码)

文章目录 0. 测试效果1. 基本内容2. 实现方法3. 代码实现4. 参考文章目录:3D视觉测量目录微信:dhlddxB站: Non-Stop_0. 测试效果 1. 基本内容 平面度是一个表达平面平整程度的度量指标,它描述了一个表面与一个理想平面之间的偏差程度。在工程和制造领域,平面度是一个重要的…

Neo-reGeorg隧道搭建

目录 Neo-regeorg前言 环境搭建 具体使用 kail安装Neo-reGeorg kail内生成webshell并设置密码 kail与win10连接 windows server内打开服务 kail虚拟机访问windows server以及所在的内网 Neo-regeorg前言 regeorg为reDuh的升级版&#xff0c;主要功能就是把内网服务器的…

windows11 利用vmware17 安装ky10-server-x86操作系统

下载相关软件和镜像 vmware17 下载 下载页面 Download VMware Workstation Pro ky10server-x86镜像下载 官网 国产操作系统、银河麒麟、中标麒麟、开放麒麟、星光麒麟——麒麟软件官方网站 (kylinos.cn) 选择对应版本去下载 安装 选择镜像&#xff0c;点击下一步 磁盘设置要…

springboot web开发静态资源的映射规则

前言 我们之间介绍过SpringBoot自动配置的原理&#xff0c;基本上是如下&#xff1a; xxxxAutoConfiguration&#xff1a;帮我们给容器中自动配置组件&#xff1b; xxxxProperties:配置类来封装配置文件的内容&#xff1b; web开发中都在org.springframework.boot.autoconfig…

一个月能做什么?成长感悟分享

一个月做了什么&#xff1f; 八月做了些什么&#xff1f; 单词打卡 第一件事情就是单词打卡 英语很差的我&#xff0c;一样继续打卡&#xff0c;今天是第736天 当你还在纠结扇贝和不背、可可英语哪一个好的时候&#xff0c;别人已经同时使用了 当你还在咨询学编程、敲代码需…

Linux上git的简单使用

git的作用&#xff1a;版本控制多人协作 客户端 磁盘上的文件-->本地仓库-->远端仓库 服务端 gitee和GitHub是基于git的商业化网站 git的命令行如何使用&#xff1f; 1、新建一个仓库 .git ignore 是忽略带有某些后缀的文件的上传。 例如&#xff1a;里面有 .sln …

输出图元(四)8-2 OpenGL画点函数、OpenGL画线函数

4.3 OpenGL画点函数 要描述一个点的几何要素&#xff0c;我们只需在世界坐标系中指定一个位置。然后该坐标位置和场景中已有的其他几何描述一起被传递给观察子程序。除非指定其他属性值&#xff0c;OpenGL 图元按默认的大小和颜色来显示。默认的图元颜色是白色&#x…

【链表OJ 10】环形链表Ⅱ(求入环节点)

前言: &#x1f4a5;&#x1f388;个人主页:​​​​​​Dream_Chaser&#xff5e; &#x1f388;&#x1f4a5; ✨✨刷题专栏:http://t.csdn.cn/UlvTc ⛳⛳本篇内容:力扣上链表OJ题目 目录 leetcode142. 环形链表 II 1.问题描述 2.代码思路 3.问题分析 leetcode142. 环形链…

案例挑战—java反射

这里写目录标题 背景一、为什么要使用反射&#xff1f;二、反射的应用反射常用应用的思维导图2.1获取class对象的三种方法示例代码 2.2利用反射获取构造方法示例代码 2.3利用反射获取成员变量示例代码 2.4利用反射获取成员方法 三、总结四、升华 背景 由于在公司自研的新项目架…

Java 乘等赋值运算

下面这个题目是在一公司发过来的&#xff0c;如果你对 Java 的赋值运算比较了解的话&#xff0c;会很快知道答案的。 这个运算符在 Java 里面叫做乘等或者乘和赋值操作符&#xff0c;它把左操作数和右操作数相乘赋值给左操作数。 例如下面的&#xff1a;density * invertedRat…

LeetCode(力扣)236. 二叉树的最近公共祖先Python

LeetCode236. 二叉树的最近公共祖先 题目链接代码 题目链接 https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/ 代码 # Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val x # self.…

微服务--SkayWalking(链路追踪:国产开源框架)

SkayWalking&#xff1a;分布式系统的应用程序性能监视工具 作用&#xff1a;分布式追踪、性能指标分析、应用、服务依赖分析&#xff1b; SkayWalking性能剖析&#xff1a; 我操&#xff0c;能够定位到某一个方法会有多慢。。。 通过Tid查看全局所有的日志信息&#xff08…

企业架构LNMP学习笔记7

PHP介绍&#xff1a; HTML&#xff1a;超文本标记语言 http: 超文本传输协议 端口80 浏览器将html代码解析成web页面。 PHP&#xff1a;超文本预处理器。后端语言开发&#xff0c;页面上需要动态改变修改的&#xff0c;需要连接数据库查询数据&#xff0c;转为html。 主要…

学习笔记230810--vue项目中get请求的两种传参方式

问题描述 今天写了一个对象方式传参的get请求接口方法&#xff0c;发现没有载荷&#xff0c;ip地址也没有带查询字符串&#xff0c;数据也没有响应。 代码展示 错误分析 实际上这里的query是对象方式带参跳转的参数名&#xff0c;而get方法对象方式传参的参数名是parmas 解…