1.代码75com中的代码.powernode.bank.webAccountservice
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视为Controler ////调用业务方法处理业务(调度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.serviceAccountservicer
package com.powernode.bank.service;import com.powernode.bank.exceptions.AppException;import com.powernode.bank.exceptions.MoneyNotEnoughException;///这是service接口 75public interface AccountService { void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException;}
com.powernode.bank.service.implAccountserviceimpllempllemplempllemple
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业务的类别。 * AccountService:专门处理Account业务的类别。 * 纯业务代码应在此类中编写。(只关注业务。不写别的。不与其他代码混合。) * 只希望专注于业务,能完美实现业务,少量bug。 * * 一般来说,业务名称:XxxService、XxxBiz... *////这一类实现了AccountService接口类 75///这一类负责处理account业务 69public 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();){ ///开启事务(Conection对象需要使用)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(”账户转账异常!= 2){ throw new AppException(“账户转帐异常!!"); } ///提交事务 connection.commit(); } catch (SQLException e) { throw new AppException(”账户转账异常!!!"); ///回滚事务(不屑也没关系) } }}
com.powernode.bank.daoAccountdao
package com.powernode.bank.dao;import com.powernode.bank.pojo.Account;import java.util.List;//这是一个接口 75public 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操作CRUDAcountdaoimpll操作
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是什么? * 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的数据操作(增删改查) 67public 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 = ? , 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.pojojavabean类Account
package com.powernode.bank.pojo;///这是Accountjavabean,负责包装数据库中的对象 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;//工具类 66public 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"); ///之所以设置为私有privatete 因为不允许创建对象,因为工具类的方法是静态的,不需要创建对象 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中删除?=null){ try { conn.close(); // 想一想:为什么conn关闭后要从大Map中删除? // 根本原因是Tomcat服务器支持线程池。也就是说,一个人用过t1线程 // ,其他用户也可以使用t1线程。 local.remove(); } catch (SQLException e) { throw new RuntimeException(e); } } }}
异常类com.powernode.bank.exceptionsAppException
package com.powernode.bank.exceptions;//app异常类别 69public class AppException extends Exception{ public AppException() { } public AppException(String msg) { super(msg); }}
MoneyNotEnoughException
package com.powernode.bank.exceptions;///钱不足异常类 69public class MoneyNotEnoughException extends Exception{ //以下是两个结构器 ///无参构造器 public MoneyNotEnoughException() { } //有参构造器 public MoneyNotEnoughException(String msg) { super(msg); }}
resourcese配置文件jdbc.properties
driver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://localhost:3306/mvcuser=rootpassword=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>