1. 代码  75

代码在com.powernode.bank.web

调度类AccountService

package com.powernode.bank.web;

import com.powernode.bank.exceptions.MoneyNotEnoughException;
import com.powernode.bank.service.AccountService;
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;

//账户servlet小程序  67和70
//AccountServlet是一个司令官。他负责调度其他组件来完成任务。
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {//把AccountServlet当作一个Controller

    //调用业务方法处理业务(调度Model处理业务)  70
    private AccountService accountService = new AccountService();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //接收数据  70
        String fromActno = request.getParameter("fromActno");
        String toActno = request.getParameter("toActno");
        double money = Double.parseDouble(request.getParameter("money"));
        //调用业务方法处理业务(调度Model处理业务)
        try {

            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) {
            //执行到这里转账失败
            //展示数据(调度view左业务展示)
            //重定向
            response.sendRedirect(request.getContextPath()+"/error.jsp");
        }

    }
}

com.powernode.bank.service

接口AccountService

package com.powernode.bank.service;

import com.powernode.bank.exceptions.AppException;
import com.powernode.bank.exceptions.MoneyNotEnoughException;

//这是一个service类接口  75
public interface AccountService {
    void transfer(String fromActno, String toActno, double money)
            throws MoneyNotEnoughException, AppException;
}

com.powernode.bank.service.impl

业务类AccountServiceImpl

package com.powernode.bank.service.impl;


import com.powernode.bank.dao.impl.AccountDaoImpl;
import com.powernode.bank.exceptions.AppException;
import com.powernode.bank.exceptions.MoneyNotEnoughException;
import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.service.AccountService;
import com.powernode.bank.utils.DBUtil;

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

/**
 * service翻译为:业务。
 * AccountService:专门处理Account业务的一个类。
 * 在该类中应该编写纯业务代码。(只专注业务。不写别的。不和其他代码混合在一块。)
 * 只希望专注业务,能够将业务完美实现,少量bug。
 *
 * 业务类一般起名:XxxService、XxxBiz.....
 */
//这个类是实现AccountService接口类  75
//这个类是负责处理account业务的  69
public class AccountServiceImpl implements AccountService {
    // 为什么定义到这里?因为在每一个业务方法中都可以需要连接数据库。
    private AccountDao accountDao = new AccountDaoImpl();//多态

    // 这里的方法起名,一定要体现出,你要处理的是什么业务。
    // 我们要提供一个能够实现转账的业务方法(一个业务对应一个方法。)
    /**
     * 完成转账的业务逻辑
     * @param fromActno 转出账号
     * @param toActno 转入账号
     * @param money 转账金额
     */
    public void transfer(String fromActno,String toActno,double money)
            throws MoneyNotEnoughException, AppException {

        //service层控制事务  71
        try (Connection connection = DBUtil.getConnection();){

            //开启事务(需要使用Connection对象)71
            connection.setAutoCommit(false);

            //查询余额是否充足(根据账号将查询到的对象封装成一个account账户返回)
            //fromAct是一个account账户对象
            Account fromAct = accountDao.selectByActno(fromActno);
            //余额不足
            if(fromAct.getBalance()<money){
                throw new MoneyNotEnoughException("对不起,余额不足");
            }
            //到这里说余额充足
            //我们继续查另一个账户余额
            //toAct是一个account账户对象
            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("账户转账异常!!!");
            //回滚事务(不屑也没关系)

        }


    }
}

com.powernode.bank.dao

接口AccountDao

package com.powernode.bank.dao;

import com.powernode.bank.pojo.Account;

import java.util.List;

//这是一个接口  75
public interface AccountDao {
    int insert(Account act);
    int deleteById(Long id);
    int update(Account act);
    Account selectByActno(String actno);
    List selectAll();
}

com.powernode.bank.dao.impl

操作CRUD类AccountDaoImpl

package com.powernode.bank.dao.impl;


import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.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;

/**
 * AccountDao是负责Account数据的增删改查的。
 * 1. 什么是DAO?
 *      Data Access Object(数据访问对象)
 * 2. DAO实际上是一种设计模式,属于JavaEE的设计模式之一。(不是23种设计模式。)
 * 3. DAO只负责数据库表的CRUD,没有任何业务逻辑在里面。
 * 4. 没有任何业务逻辑,只负责表中数据增删改查的对象,有一个特殊的称谓:DAO对象。
 * 5. 为什么叫做AccountDao呢?
 *      这是因为这个DAO是专门处理t_act这张表的。
 *      如果处理t_user表的话,可以叫做:UserDao
 *      如果处理t_student表的话,可以叫做:StudentDao
 * 6. 一般情况下:一张表会对应一个DAO对象。
 * 7. DAO中的方法名很固定了,一般都是:
 *      insert
 *      deleteByXxx
 *      update
 *      selectByXxx
 *      selectAll
 */
//这个类是实现AccountDao接口  75
//这个类负责Account的数据操作(增删改查)  67
public class AccountDaoImpl implements AccountDao {
    //负责往数据库中插入账户信息  67
    //之所以是int类是因为,插入操作返回的是受影响的行数
    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();
        }finally {
            //关闭资源
            DBUtil.close(null,ps,null);
        }
        return count;
    }

    //删除数据(根据id删除)  67
    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 0;
    }

    //更新数据  67
    public int update(Account act){
        PreparedStatement ps = null;
        int count = 0;
        try {
            Connection conn = DBUtil.getConnection();
            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;
    }

    //根据账号查找数据  67
    public Account selectByActno(String actno){

        PreparedStatement ps = null;
        ResultSet rs = null;
        Account act = null;
        try {
            Connection 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();
                act.setId(id);
                act.setActno(actno);
                act.setBalance(balance);
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(null, ps, rs);
        }

        return act;
    }

    //获取所有的账户  67
    public List selectAll(){
        PreparedStatement ps = null;
        ResultSet rs = null;
        List 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;
    }
}

com.powernode.bank.pojo

javabean类Account 

package com.powernode.bank.pojo;

//这是一个Account的javabean负责封装数据库里的对象  67
/**
 * 账户实体类:封装账户信息的。
 * 一般是一张表一个。
 * pojo对象。
 * 有的人也会把这种专门封装数据的对象,称为bean对象。(javabean:咖啡豆)
 * 有的人也会把这种专门封装数据的对象,称为领域模型对象。domain对象。
 * 不同的程序员有不同的习惯。
 *
 * pojo、bean、domain.....
 */
public class Account {  // 这种普通简单的对象被成为pojo对象。
    // 一般这种属性不建议设计为基本数据类型,建议使用包装类。防止null带来的问题。
    //private long id;
    private Long id;  //主键

    private String actno;//账号

    //private double balance;
    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 String () {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
}

com.powernode.bank.utils

工具类DBUtil

package com.powernode.bank.utils;

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

//工具类  66
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 是因为不让创建对象,因为工具类中的方法都是静态的,不需要创建对象
    private DBUtil(){};

    //DBUtil类加载时注册驱动
    static {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //获取ThreadLocal对象   73
    //这个对象实际上在服务器中只有一个  73
    private static ThreadLocal local = new ThreadLocal<>();

    //获取连接对象
    //这里没有使用数据库连接池,直接创建连接对象。
    //返回连接对象
    public static Connection getConnection() throws SQLException {

        Connection conn = local.get();
        if(conn==null){//判断为不为空(因为第一次访问conn肯定为空)
            //为空就获取一个新的conn
            conn = DriverManager.getConnection(url, user, password);
            //将conn放入
            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);
            }
        }
    }

}

异常类com.powernode.bank.exceptions

AppException

package com.powernode.bank.exceptions;

//app异常类  69
public class AppException extends Exception{
    public AppException() {
    }

    public AppException(String msg) {
        super(msg);
    }
}

MoneyNotEnoughException

package com.powernode.bank.exceptions;

//钱不足异常类  69
public class MoneyNotEnoughException extends Exception{
    //以下是两个构造器
    //无参构造器
    public MoneyNotEnoughException() {
    }
    //有参构造器
    public MoneyNotEnoughException(String msg) {
        super(msg);
    }
}

配置文件 resources

 jdbc.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mvc
user=root
password=lzl

index.jsp

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

error.jsp

<%--转账失败页面 70--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>转账失败</title>
</head>
<body>
<h1>转账失败</h1>
</body>
</html>

moneynotenough.jsp

<%--余额不足页面  70--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>转账失败</title>
</head>
<body>
<h1>余额不足</h1>
</body>
</html>

success.jsp

<%--转账成功页面  70--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>转账成功</title>
</head>
<body>
<h1>转账成功</h1>
</body>
</html>

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6