MVC架构模式
对Model进一步细化
Controller+View等于Web层/表现层
第一步:定义Account类
package com.huhu.bank.mvc;
/**
* 账户实体类,封装账户信息
*/
public class Account {
//一般属性不建议设计为基本数据类型,建议使用包装类,防止null带来问题
private Long id;
private String actno;
private Double balance;
public Account(Long id, String actno, Double balance) {
this.id = id;
this.actno = actno;
this.balance = balance;
}
public Account() {
}
@Override
public 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;
}
}
第二步:定义Dao层
package com.huhu.bank.mvc;
import com.huhu.bank.utils.DBUtil;
import java.sql.*;
import java.util.*;
/**
* 负责Account数据的增删改查
* DAO数据访问对象
* 只负责数据库的CRUD,没有任何业务逻辑在里面
*/
public class AccountDao {
public int insert(Account act) {
Connection con = null;
PreparedStatement ps = null;
int count = 0;
try {
con = DBUtil.getConnection();
String sql = "insert into t_act(actno,balance) values(?,?)";
ps = con.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(con, ps, null);
}
return count;
}
public int deleteById(String id) {
Connection con = null;
PreparedStatement ps = null;
int count = 0;
try {
con = DBUtil.getConnection();
String sql = "delete from t_act where id=?";
ps = con.prepareStatement(sql);
ps.setString(1, id);
count = ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(con, ps, null);
}
return count;
}
public int update(Account act) {
Connection con = null;
PreparedStatement ps = null;
int count = 0;
try {
con = DBUtil.getConnection();
String sql = "update t_act set balance=?,actno=? where id=? ";
ps = con.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(con, ps, null);
}
return count;
}
public Account selectByActno(String actno) {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
Account act = null;
try {
con = DBUtil.getConnection();
String sql = "select id,actno,balance from t_act where actno=?";
ps = con.prepareStatement(sql);
ps.setString(1, actno);
rs = ps.executeQuery();
if (rs.next()) {
Long id = rs.getLong("id");
double balance = rs.getDouble("balance");
//将结果集封装成对象
act = new Account();
act.setId(id);
act.setActno(actno);
act.setBalance(balance);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(con, ps, null);
}
return act;
}
public List<Account> selectAll() {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
List<Account> list = new ArrayList<>();
try {
con = DBUtil.getConnection();
String sql = "select id,actno,balance from t_act";
ps = con.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集合
list.add(account);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(con, ps, null);
}
return list;
}
}
第三步:定义业务层
package com.huhu.bank.mvc;
import com.huhu.bank.exceptions.AppException;
import com.huhu.bank.exceptions.MoneyNotEnoughException;
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);
fromAct.setBalance(fromAct.getBalance() - money);
toAct.setBalance(toAct.getBalance() + money);
//更新数据库中余额
int count = accountDao.update(fromAct);
count += accountDao.update(toAct);
if (count!=2){
throw new AppException("账户转账异常!!!");
}
}
}
第四步:定义表现层
package com.huhu.bank.mvc;
import com.huhu.bank.exceptions.MoneyNotEnoughException;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.*;
/**
* 账户小程序
* 司令官。负责调度其他组件完成任务
*/
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {
private AccountService accountService = new AccountService();
@Override
protected 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"));
//调用业务方法处理业务(调用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");
}
}
}
工具类
package com.huhu.bank.utils;
import java.sql.*;
import java.util.*;
import static java.util.ResourceBundle.*;
/**
* JDBC工具类封装
*/
public class DBUtil {
private static ResourceBundle bundle = 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();
}
}
/**
* 这里没有使用数据库连接池,直接创建连接对象
* @return 连接对象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
Connection con=DriverManager.getConnection(url,user,password);
return con;
}
/**
* 关闭资源
* @param con 连接对象
* @param stmt 数据库操作对象
* @param rs 结果集对象
*/
public static void close(Connection con,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 (con!=null){
try {
con.close();
}catch (SQLException e){
throw new RuntimeException(e);
}
}
}
}
事务银行转账优化篇
工具类
private static ThreadLocal<Connection> local=new ThreadLocal<>();
/**
* 这里没有使用数据库连接池,直接创建连接对象
* @return 连接对象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
Connection con = local.get();
if (con==null){
con=DriverManager.getConnection(url,user,password);
local.set(con);
}
return con;
}
if (con!=null){
try {
con.close();
//根本原因:Tomcat支持线程池的,一个人使用过t1线程,不移除的话可能会被其他人使用
local.remove();
}catch (SQLException e){
throw new RuntimeException(e);
}
}
Service层类
package com.huhu.bank.mvc;
import com.huhu.bank.exceptions.AppException;
import com.huhu.bank.exceptions.MoneyNotEnoughException;
import com.huhu.bank.utils.DBUtil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
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 con= DBUtil.getConnection()){
System.out.println(con);
con.setAutoCommit(false);
//查询余额是否充足
Account fromAct = accountDao.selectByActno(fromActno);
if (fromAct.getBalance() < money) {
throw new MoneyNotEnoughException("对不起,余额不足!");
}
//余额充足
Account toAct = accountDao.selectByActno(toActno);
fromAct.setBalance(fromAct.getBalance() - money);
toAct.setBalance(toAct.getBalance() + money);
//更新数据库中余额
int count = accountDao.update(fromAct);
count += accountDao.update(toAct);
//模拟异常
String s=null;
s.toString();
if (count!=2){
throw new AppException("账户转账异常!!!");
}
con.commit();
}catch (SQLException e){
throw new AppException("账户转账异常!!!");
}
}
}
Dao类
package com.huhu.bank.mvc;
import com.huhu.bank.utils.DBUtil;
import java.sql.*;
import java.util.*;
/**
* 负责Account数据的增删改查
* DAO数据访问对象
* 只负责数据库的CRUD,没有任何业务逻辑在里面
*/
public class AccountDao {
public int insert(Account act) {
PreparedStatement ps = null;
int count = 0;
try {
Connection con = DBUtil.getConnection();
String sql = "insert into t_act(actno,balance) values(?,?)";
ps = con.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;
}
public int deleteById(String id) {
PreparedStatement ps = null;
int count = 0;
try {
Connection con = DBUtil.getConnection();
String sql = "delete from t_act where id=?";
ps = con.prepareStatement(sql);
ps.setString(1, id);
count = ps.executeUpdate();
} catch (SQLException e) {
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 con = DBUtil.getConnection();
String sql = "update t_act set balance=?,actno=? where id=? ";
ps = con.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;
}
public Account selectByActno(String actno) {
PreparedStatement ps = null;
ResultSet rs = null;
Account act = null;
try {
Connection con = DBUtil.getConnection();
String sql = "select id,actno,balance from t_act where actno=?";
ps = con.prepareStatement(sql);
ps.setString(1, actno);
rs = ps.executeQuery();
if (rs.next()) {
Long id = rs.getLong("id");
double balance = rs.getDouble("balance");
//将结果集封装成对象
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;
}
public List<Account> selectAll() {
PreparedStatement ps = null;
ResultSet rs = null;
List<Account> list = new ArrayList<>();
try {
Connection con = DBUtil.getConnection();
String sql = "select id,actno,balance from t_act";
ps = con.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集合
list.add(account);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(null, ps, rs);
}
return list;
}
}