• MVC架构模式实现银行转账


     MVC架构模式

     对Model进一步细化

     Controller+View等于Web层/表现层 

     第一步:定义Account类

    1. package com.huhu.bank.mvc;
    2. /**
    3. * 账户实体类,封装账户信息
    4. */
    5. public class Account {
    6. //一般属性不建议设计为基本数据类型,建议使用包装类,防止null带来问题
    7. private Long id;
    8. private String actno;
    9. private Double balance;
    10. public Account(Long id, String actno, Double balance) {
    11. this.id = id;
    12. this.actno = actno;
    13. this.balance = balance;
    14. }
    15. public Account() {
    16. }
    17. @Override
    18. public String toString() {
    19. return "Account{" +
    20. "id=" + id +
    21. ", actno='" + actno + '\'' +
    22. ", balance=" + balance +
    23. '}';
    24. }
    25. public Long getId() {
    26. return id;
    27. }
    28. public void setId(Long id) {
    29. this.id = id;
    30. }
    31. public String getActno() {
    32. return actno;
    33. }
    34. public void setActno(String actno) {
    35. this.actno = actno;
    36. }
    37. public Double getBalance() {
    38. return balance;
    39. }
    40. public void setBalance(Double balance) {
    41. this.balance = balance;
    42. }
    43. }

    第二步:定义Dao层

    1. package com.huhu.bank.mvc;
    2. import com.huhu.bank.utils.DBUtil;
    3. import java.sql.*;
    4. import java.util.*;
    5. /**
    6. * 负责Account数据的增删改查
    7. * DAO数据访问对象
    8. * 只负责数据库的CRUD,没有任何业务逻辑在里面
    9. */
    10. public class AccountDao {
    11. public int insert(Account act) {
    12. Connection con = null;
    13. PreparedStatement ps = null;
    14. int count = 0;
    15. try {
    16. con = DBUtil.getConnection();
    17. String sql = "insert into t_act(actno,balance) values(?,?)";
    18. ps = con.prepareStatement(sql);
    19. ps.setString(1, act.getActno());
    20. ps.setDouble(2, act.getBalance());
    21. count = ps.executeUpdate();
    22. } catch (SQLException e) {
    23. throw new RuntimeException(e);
    24. } finally {
    25. DBUtil.close(con, ps, null);
    26. }
    27. return count;
    28. }
    29. public int deleteById(String id) {
    30. Connection con = null;
    31. PreparedStatement ps = null;
    32. int count = 0;
    33. try {
    34. con = DBUtil.getConnection();
    35. String sql = "delete from t_act where id=?";
    36. ps = con.prepareStatement(sql);
    37. ps.setString(1, id);
    38. count = ps.executeUpdate();
    39. } catch (SQLException e) {
    40. throw new RuntimeException(e);
    41. } finally {
    42. DBUtil.close(con, ps, null);
    43. }
    44. return count;
    45. }
    46. public int update(Account act) {
    47. Connection con = null;
    48. PreparedStatement ps = null;
    49. int count = 0;
    50. try {
    51. con = DBUtil.getConnection();
    52. String sql = "update t_act set balance=?,actno=? where id=? ";
    53. ps = con.prepareStatement(sql);
    54. ps.setDouble(1, act.getBalance());
    55. ps.setString(2, act.getActno());
    56. ps.setLong(3, act.getId());
    57. count = ps.executeUpdate();
    58. } catch (SQLException e) {
    59. throw new RuntimeException(e);
    60. } finally {
    61. DBUtil.close(con, ps, null);
    62. }
    63. return count;
    64. }
    65. public Account selectByActno(String actno) {
    66. Connection con = null;
    67. PreparedStatement ps = null;
    68. ResultSet rs = null;
    69. Account act = null;
    70. try {
    71. con = DBUtil.getConnection();
    72. String sql = "select id,actno,balance from t_act where actno=?";
    73. ps = con.prepareStatement(sql);
    74. ps.setString(1, actno);
    75. rs = ps.executeQuery();
    76. if (rs.next()) {
    77. Long id = rs.getLong("id");
    78. double balance = rs.getDouble("balance");
    79. //将结果集封装成对象
    80. act = new Account();
    81. act.setId(id);
    82. act.setActno(actno);
    83. act.setBalance(balance);
    84. }
    85. } catch (SQLException e) {
    86. throw new RuntimeException(e);
    87. } finally {
    88. DBUtil.close(con, ps, null);
    89. }
    90. return act;
    91. }
    92. public List selectAll() {
    93. Connection con = null;
    94. PreparedStatement ps = null;
    95. ResultSet rs = null;
    96. List list = new ArrayList<>();
    97. try {
    98. con = DBUtil.getConnection();
    99. String sql = "select id,actno,balance from t_act";
    100. ps = con.prepareStatement(sql);
    101. rs = ps.executeQuery();
    102. while (rs.next()) {
    103. //取出数据
    104. Long id = rs.getLong("id");
    105. String actno = rs.getString("actno");
    106. double balance = rs.getDouble("balance");
    107. //封装对象
    108. Account account = new Account();
    109. account.setId(id);
    110. account.setActno(actno);
    111. account.setBalance(balance);
    112. //加到List集合
    113. list.add(account);
    114. }
    115. } catch (SQLException e) {
    116. throw new RuntimeException(e);
    117. } finally {
    118. DBUtil.close(con, ps, null);
    119. }
    120. return list;
    121. }
    122. }

    第三步:定义业务层

    1. package com.huhu.bank.mvc;
    2. import com.huhu.bank.exceptions.AppException;
    3. import com.huhu.bank.exceptions.MoneyNotEnoughException;
    4. public class AccountService {
    5. private AccountDao accountDao=new AccountDao();
    6. /**
    7. * 完成转账业务逻辑
    8. *
    9. * @param fromActno
    10. * @param toActno
    11. * @param money
    12. */
    13. public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
    14. //查询余额是否充足
    15. Account fromAct = accountDao.selectByActno(fromActno);
    16. if (fromAct.getBalance() < money) {
    17. throw new MoneyNotEnoughException("对不起,余额不足!");
    18. }
    19. //余额充足
    20. Account toAct = accountDao.selectByActno(toActno);
    21. fromAct.setBalance(fromAct.getBalance() - money);
    22. toAct.setBalance(toAct.getBalance() + money);
    23. //更新数据库中余额
    24. int count = accountDao.update(fromAct);
    25. count += accountDao.update(toAct);
    26. if (count!=2){
    27. throw new AppException("账户转账异常!!!");
    28. }
    29. }
    30. }

    第四步:定义表现层 

    1. package com.huhu.bank.mvc;
    2. import com.huhu.bank.exceptions.MoneyNotEnoughException;
    3. import javax.servlet.*;
    4. import javax.servlet.annotation.WebServlet;
    5. import javax.servlet.http.*;
    6. import java.io.*;
    7. /**
    8. * 账户小程序
    9. * 司令官。负责调度其他组件完成任务
    10. */
    11. @WebServlet("/transfer")
    12. public class AccountServlet extends HttpServlet {
    13. private AccountService accountService = new AccountService();
    14. @Override
    15. protected void doPost(HttpServletRequest request, HttpServletResponse response)
    16. throws ServletException, IOException {
    17. //接收数据
    18. String fromActno = request.getParameter("fromActno");
    19. String toActno = request.getParameter("toActno");
    20. Double money = Double.parseDouble(request.getParameter("money"));
    21. //调用业务方法处理业务(调用model处理业务)
    22. try {
    23. accountService.transfer(fromActno, toActno, money);
    24. //转账成功
    25. //展示处理结果(调用view作页面展示)
    26. response.sendRedirect(request.getContextPath() + "/success.jsp");
    27. } catch (MoneyNotEnoughException e) {
    28. //余额不足
    29. //展示处理结果(调用view作页面展示)
    30. response.sendRedirect(request.getContextPath() + "/moneyNotEnough.jsp");
    31. } catch (Exception e) {
    32. //转账失败
    33. //展示处理结果(调用view作页面展示)
    34. response.sendRedirect(request.getContextPath() + "/error.jsp");
    35. }
    36. }
    37. }

    工具类

    1. package com.huhu.bank.utils;
    2. import java.sql.*;
    3. import java.util.*;
    4. import static java.util.ResourceBundle.*;
    5. /**
    6. * JDBC工具类封装
    7. */
    8. public class DBUtil {
    9. private static ResourceBundle bundle = getBundle("resources/jdbc");
    10. private static String driver = bundle.getString("driver");
    11. private static String url = bundle.getString("url");
    12. private static String user = bundle.getString("user");
    13. private static String password = bundle.getString("password");
    14. /**
    15. * 私有构造方法
    16. * 不让创建对象,因为工具类中方法都是静态的,不需要创建对象
    17. * 为了防止创建对象,因此将方法私有化
    18. */
    19. private DBUtil() {}
    20. //DBUtil类加载注册驱动
    21. static {
    22. try {
    23. Class.forName(driver);
    24. }catch (ClassNotFoundException e){
    25. e.printStackTrace();
    26. }
    27. }
    28. /**
    29. * 这里没有使用数据库连接池,直接创建连接对象
    30. * @return 连接对象
    31. * @throws SQLException
    32. */
    33. public static Connection getConnection() throws SQLException {
    34. Connection con=DriverManager.getConnection(url,user,password);
    35. return con;
    36. }
    37. /**
    38. * 关闭资源
    39. * @param con 连接对象
    40. * @param stmt 数据库操作对象
    41. * @param rs 结果集对象
    42. */
    43. public static void close(Connection con,Statement stmt,ResultSet rs){
    44. if (rs!=null){
    45. try {
    46. rs.close();
    47. }catch (SQLException e){
    48. throw new RuntimeException(e);
    49. }
    50. }
    51. if (stmt!=null){
    52. try {
    53. stmt.close();
    54. }catch (SQLException e){
    55. throw new RuntimeException(e);
    56. }
    57. }
    58. if (con!=null){
    59. try {
    60. con.close();
    61. }catch (SQLException e){
    62. throw new RuntimeException(e);
    63. }
    64. }
    65. }
    66. }

    事务银行转账优化篇 

    工具类

    1. private static ThreadLocal local=new ThreadLocal<>();
    2. /**
    3. * 这里没有使用数据库连接池,直接创建连接对象
    4. * @return 连接对象
    5. * @throws SQLException
    6. */
    7. public static Connection getConnection() throws SQLException {
    8. Connection con = local.get();
    9. if (con==null){
    10. con=DriverManager.getConnection(url,user,password);
    11. local.set(con);
    12. }
    13. return con;
    14. }
    1. if (con!=null){
    2. try {
    3. con.close();
    4. //根本原因:Tomcat支持线程池的,一个人使用过t1线程,不移除的话可能会被其他人使用
    5. local.remove();
    6. }catch (SQLException e){
    7. throw new RuntimeException(e);
    8. }
    9. }

     Service层类

    1. package com.huhu.bank.mvc;
    2. import com.huhu.bank.exceptions.AppException;
    3. import com.huhu.bank.exceptions.MoneyNotEnoughException;
    4. import com.huhu.bank.utils.DBUtil;
    5. import java.sql.Connection;
    6. import java.sql.DriverManager;
    7. import java.sql.SQLException;
    8. public class AccountService {
    9. private AccountDao accountDao=new AccountDao();
    10. /**
    11. * 完成转账业务逻辑
    12. *
    13. * @param fromActno
    14. * @param toActno
    15. * @param money
    16. */
    17. public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
    18. //Service层控制事务
    19. try(Connection con= DBUtil.getConnection()){
    20. System.out.println(con);
    21. con.setAutoCommit(false);
    22. //查询余额是否充足
    23. Account fromAct = accountDao.selectByActno(fromActno);
    24. if (fromAct.getBalance() < money) {
    25. throw new MoneyNotEnoughException("对不起,余额不足!");
    26. }
    27. //余额充足
    28. Account toAct = accountDao.selectByActno(toActno);
    29. fromAct.setBalance(fromAct.getBalance() - money);
    30. toAct.setBalance(toAct.getBalance() + money);
    31. //更新数据库中余额
    32. int count = accountDao.update(fromAct);
    33. count += accountDao.update(toAct);
    34. //模拟异常
    35. String s=null;
    36. s.toString();
    37. if (count!=2){
    38. throw new AppException("账户转账异常!!!");
    39. }
    40. con.commit();
    41. }catch (SQLException e){
    42. throw new AppException("账户转账异常!!!");
    43. }
    44. }
    45. }

    Dao类 

    1. package com.huhu.bank.mvc;
    2. import com.huhu.bank.utils.DBUtil;
    3. import java.sql.*;
    4. import java.util.*;
    5. /**
    6. * 负责Account数据的增删改查
    7. * DAO数据访问对象
    8. * 只负责数据库的CRUD,没有任何业务逻辑在里面
    9. */
    10. public class AccountDao {
    11. public int insert(Account act) {
    12. PreparedStatement ps = null;
    13. int count = 0;
    14. try {
    15. Connection con = DBUtil.getConnection();
    16. String sql = "insert into t_act(actno,balance) values(?,?)";
    17. ps = con.prepareStatement(sql);
    18. ps.setString(1, act.getActno());
    19. ps.setDouble(2, act.getBalance());
    20. count = ps.executeUpdate();
    21. } catch (SQLException e) {
    22. throw new RuntimeException(e);
    23. } finally {
    24. DBUtil.close(null, ps, null);
    25. }
    26. return count;
    27. }
    28. public int deleteById(String id) {
    29. PreparedStatement ps = null;
    30. int count = 0;
    31. try {
    32. Connection con = DBUtil.getConnection();
    33. String sql = "delete from t_act where id=?";
    34. ps = con.prepareStatement(sql);
    35. ps.setString(1, id);
    36. count = ps.executeUpdate();
    37. } catch (SQLException e) {
    38. throw new RuntimeException(e);
    39. } finally {
    40. DBUtil.close(null, ps, null);
    41. }
    42. return count;
    43. }
    44. public int update(Account act) {
    45. PreparedStatement ps = null;
    46. int count = 0;
    47. try {
    48. Connection con = DBUtil.getConnection();
    49. String sql = "update t_act set balance=?,actno=? where id=? ";
    50. ps = con.prepareStatement(sql);
    51. ps.setDouble(1, act.getBalance());
    52. ps.setString(2, act.getActno());
    53. ps.setLong(3, act.getId());
    54. count = ps.executeUpdate();
    55. } catch (SQLException e) {
    56. throw new RuntimeException(e);
    57. } finally {
    58. DBUtil.close(null, ps, null);
    59. }
    60. return count;
    61. }
    62. public Account selectByActno(String actno) {
    63. PreparedStatement ps = null;
    64. ResultSet rs = null;
    65. Account act = null;
    66. try {
    67. Connection con = DBUtil.getConnection();
    68. String sql = "select id,actno,balance from t_act where actno=?";
    69. ps = con.prepareStatement(sql);
    70. ps.setString(1, actno);
    71. rs = ps.executeQuery();
    72. if (rs.next()) {
    73. Long id = rs.getLong("id");
    74. double balance = rs.getDouble("balance");
    75. //将结果集封装成对象
    76. act = new Account();
    77. act.setId(id);
    78. act.setActno(actno);
    79. act.setBalance(balance);
    80. }
    81. } catch (SQLException e) {
    82. throw new RuntimeException(e);
    83. } finally {
    84. DBUtil.close(null, ps, rs);
    85. }
    86. return act;
    87. }
    88. public List selectAll() {
    89. PreparedStatement ps = null;
    90. ResultSet rs = null;
    91. List list = new ArrayList<>();
    92. try {
    93. Connection con = DBUtil.getConnection();
    94. String sql = "select id,actno,balance from t_act";
    95. ps = con.prepareStatement(sql);
    96. rs = ps.executeQuery();
    97. while (rs.next()) {
    98. //取出数据
    99. Long id = rs.getLong("id");
    100. String actno = rs.getString("actno");
    101. double balance = rs.getDouble("balance");
    102. //封装对象
    103. Account account = new Account();
    104. account.setId(id);
    105. account.setActno(actno);
    106. account.setBalance(balance);
    107. //加到List集合
    108. list.add(account);
    109. }
    110. } catch (SQLException e) {
    111. throw new RuntimeException(e);
    112. } finally {
    113. DBUtil.close(null, ps, rs);
    114. }
    115. return list;
    116. }
    117. }

  • 相关阅读:
    uniapp项目+SSM实现的安卓的掌上校园系统
    病毒攻防原理
    基于 JuiceFS 构建高校 AI 存储方案:高并发、系统稳定、运维简单
    SpringMVC篇
    rpc通信的实现方式(以grpc为例)
    基础线段树
    TC8:UDP_USER_INTERFACE_01-08
    Kubectl 的使用——k8s陈述式资源管理
    云原生周刊 | 波音公司允许员工给开源项目做贡献
    Java 性能基准测试:从 OpenJDK 8 到 OpenJDK 19
  • 原文地址:https://blog.csdn.net/bubbleJessica/article/details/128189777