前言
上一篇文章中,我们对水果库存系统的需求进行了介绍,同时对系统需要的结构进行了设计,接下来,就到了实际上手,实现功能的阶段了。
在这篇文章中,我们将对实现类FruitDAOImpl中的单精度方法进行代码实现。
回顾一下实现类FruitDAOImpl中设计的单精度方法吧:
👇查询库存列表:
List< Fruit > getFruitList();
👇 新增库存:
boolean addFruit(Fruit fruit);
👇 修改库存:
boolean UpdateFruit(Fruit fruit);
👇删除库存:
boolean DelFruit(String fname);
👇查询指定库存:
Fruit getFruitByFname(String fname);
接口实现类FruitDAOImpl的功能实现
一、更新操作相关
1. boolean addFruit(Fruit fruit);
这是新增库存的方法,根据字面意思来简单理解一下,就是使用JDBC连接数据库,对数据库数据进行增添操作,增添的数据来自传入的Fruit对象。
依旧是常规的步骤:
…
加载驱动:
//加载驱动 Class.forName("com.mysql.cj.jdbc.Driver");
…
使用数据库管理器,连接数据库:
需要准备:
连接数据库的地址URL;
数据库账户USER;
账户密码PSW(password);
String URL = "jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&CharacterEncoding=utf-8"; String USER = "root" ; String PSW = "" ; //数据库管理器,连接数据库 Connection connection = DriverManager.getConnection(URL, USER, PSW);
…
编写SQL语句:
因为第一个属性fid(水果编号)是自增列,所以填入0即可。
剩下的四个属性,使用占位符 ?代替,以便后续的填充。
String sql = "insert into t_fruit values(0,?,?,?,?)";
…
创建预处理对象:
将编写的SQL语句传入;
PreparedStatement pstm = connection.prepareStatement(sql);
…
填充占位符 ?参数:
这里面的参数需要从传入的Fruit对象中获取,也就是:
fruit.getFname()
fruit.getPrice()
fruit.getFcount()
fruit.getRemark()
pstm.setString(1, fruit.getFname()); pstm.setInt(2,fruit.getPrice()); pstm.setInt(3,fruit.getFcount()); pstm.setString(4,fruit.getRemark());
…
执行更新,返回影响行数:
int count = pstm.executeUpdate()
因为boolean addFruit(Fruit fruit);方法的返回值是布尔类型(boolean),所以当返回的影响行数大于零时,我们就返回true,否则返回false
return count > 0;
…
关闭资源:
很重要的一步:
psmt.close(); connection.close();
…
完成这一系列的操作,我们得到了:
满屏的报错,对了,我们还需要异常处理:try-catch-finally
@Override public boolean addFruit(Fruit fruit){ try { Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&characterEncoding=gbk", "root", ""); String sql = "insert into t_fruit values(8,?,?,?,?)"; PreparedStatement psmt = connection.prepareStatement(sql); pstm.setString(1, fruit.getFname()); pstm.setInt(2,fruit.getPrice()); pstm.setInt(3,fruit.getFcount()); pstm.setString(4,fruit.getRemark()); int count = psmt.executeUpdate(); return count > 0; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally{ try { if(psmt != null) psmt.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return false; }
但是,依旧爆红:
这是因为我们经过异常处理之后,创建的对象,都被try{}代码块给囊括起来了,而出了代码块之后也就失去了效用,所以在finally{}中的对象会出问题…
为了解决这个问题,我们就需要将对象都设置成全局变量,这样的话,无论在那个代码块中,都能被识别出来。
同时,还可以将一些比较冗长,常常用到的属性也设置成全局变量,方便使用。
final String DRIVER = "com.mysql.cj.jdbc.Driver"; final String URL = "jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&CharacterEncoding=utf-8"; final String USER = "root" ; final String PSW = "" ; Connection connection; PreparedStatement pstm; ResultSet rs; List<Fruit> list;
这样子,问题基本就解决啦:
@Override public boolean addFruit(Fruit fruit){ try { Class.forName(DRIVER); connection = DriverManager.getConnection(URL, USER, PSW); String sql = "insert into t_fruit values(0,?,?,?,?)"; pstm = connection.prepareStatement(sql); pstm.setString(1, fruit.getFname()); pstm.setInt(2,fruit.getPrice()); pstm.setInt(3,fruit.getFcount()); pstm.setString(4,fruit.getRemark()); return pstm.executeUpdate() > 0; } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ try { if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return false; }
上文介绍的功能实现,步骤已经十分齐全,而且在接下来的更新操作相关方法中,除了SQL语句,基本上都大同小异了。
2.boolean UpdateFruit(Fruit fruit);
在更新水果库存方法中,我们只需要更新指定水果的库存数量即可,所以需要填充的参数有两个,都是从传入的Fruit对象(已修改库存)中获取:
fruit.getFname() — 获取水果名称
fruit.getFcount() — 获取水果库存
功能实现代码:
@Override public boolean UpdateFruit(Fruit fruit) { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "update t_fruit set fcount = ? where fname like ?"; //预处理对象 pstm = connection.prepareStatement(sql); pstm.setInt(1,fruit.getFcount()); pstm.setString(2, fruit.getFname()); return pstm.executeUpdate() > 0; } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ try { if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return false; }
3.boolean DelFruit(String fname)
删除库存的方法里,只需要根据传入的水果名称,删除数据库中相应的数据即可:
功能实现的代码:
@Override public boolean DelFruit(String fname) { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "delete from t_fruit where fname like ?"; //预处理对象 pstm = connection.prepareStatement(sql); pstm.setString(1,fname); return pstm.executeUpdate() > 0; } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ try { if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return false; }
二、查询操作相关
1.List getFruitList()
执行查询操作与执行更新操作之间有一定的差异:
查询操作通常调用的是预处理对象的executeQuery()方法
更新操作通常调用的是预处理对象的executeUpdate()方法
executeUpdate()方法返回的是更新操作后的影响行数;
而executeQuery()方法返回的是一个 ResultSet对象,里面存储的是记录了数据库每行信息的数据。
我们需要使用循环来将数据库每行信息记录下来,存储进数组中返回。
集合在上文已经设置成了全局变量:
ResultSet rs; //rs对象 List<Fruit> list; //集合
查询水果信息的实现代码:
@Override public List<Fruit> getFruitList() { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "select * from t_fruit"; //预处理对象 pstm = connection.prepareStatement(sql); //执行查询,返回结果集 rs = pstm.executeQuery(); list = new ArrayList<Fruit>(); while(rs.next()){ int Fid = rs.getInt("fid"); String Fname = rs.getString("fname"); int Price = rs.getInt("price"); int Fcount = rs.getInt("fcount"); String Remark = rs.getString("remark"); Fruit fruitTable = new Fruit(Fid,Fname,Price,Fcount,Remark); list.add(fruitTable); } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ try { if(rs != null) rs.close(); if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return list; }
2.Fruit getFruitByFname(String fname)
查询指定水果的信息,在这个方法中,我们依靠传入的水果姓名-fname来确定需要查询信息的水果。
返回的是Fruit对象,此对象的属性便是指定水果的信息。
@Override public Fruit getFruitByFname(String fname) { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "select * from t_fruit where fname = ? "; //预处理对象 pstm = connection.prepareStatement(sql); pstm.setString(1,fname); //执行查询,返回结果集 rs = pstm.executeQuery(); while(rs.next()){ int fid = rs.getInt("fid"); int price = rs.getInt("price"); int fcount = rs.getInt("fcount"); String remark = rs.getString("remark"); Fruit fruit = new Fruit(fid,fname,price,fcount,remark); return fruit; } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ try { if(rs != null) rs.close(); if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return null; }
三、代码汇总
接口实现类FruitDAOImpl中出现的方法,全都是单精度方法,代表方法的颗粒密度已经不能再划分了。
简单点来说,方法的功能还过于单一,操作过于简易,而不足以满足水果库存系统的功能需求。
也正因如此,我们还需要菜单类Menu中的方法,里面的方法调用了接口实现类FruitDAOImpl这里的单精度方法,同时将拥有更加丰富的功能。
接口实现类FruitDAOImpl的功能实现:
import com.haojin.fruit.dao.FruitDAO; import com.haojin.fruit.pojo.Fruit; import java.sql.*; import java.util.ArrayList; import java.util.List; /** * @author .29. * @create 2022-09-23 17:56 */ class FruitDAOImpl implements FruitDAO { final String DRIVER = "com.mysql.cj.jdbc.Driver"; final String URL = "jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&CharacterEncoding=utf-8"; final String USER = "root" ; final String PSW = "" ; Connection connection; PreparedStatement pstm; ResultSet rs; List<Fruit> list; @Override public List<Fruit> getFruitList() { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "select * from t_fruit"; //预处理对象 pstm = connection.prepareStatement(sql); //执行查询,返回结果集 rs = pstm.executeQuery(); list = new ArrayList<Fruit>(); while(rs.next()){ int Fid = rs.getInt("fid"); String Fname = rs.getString("fname"); int Price = rs.getInt("price"); int Fcount = rs.getInt("fcount"); String Remark = rs.getString("remark"); Fruit fruitTable = new Fruit(Fid,Fname,Price,Fcount,Remark); list.add(fruitTable); } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ try { if(rs != null) rs.close(); if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return list; } @Override public boolean addFruit(Fruit fruit){ try { Class.forName(DRIVER); connection = DriverManager.getConnection(URL, USER, PSW); String sql = "insert into t_fruit values(0,?,?,?,?)"; pstm = connection.prepareStatement(sql); pstm.setString(1, fruit.getFname()); pstm.setInt(2,fruit.getPrice()); pstm.setInt(3,fruit.getFcount()); pstm.setString(4,fruit.getRemark()); return pstm.executeUpdate() > 0; } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ try { if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return false; } @Override public boolean UpdateFruit(Fruit fruit) { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "update t_fruit set fcount = ? where fname like ?"; //预处理对象 pstm = connection.prepareStatement(sql); pstm.setInt(1,fruit.getFcount()); pstm.setString(2, fruit.getFname()); return pstm.executeUpdate() > 0; } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ try { if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return false; } @Override public boolean DelFruit(String fname) { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "delete from t_fruit where fname like ?"; //预处理对象 pstm = connection.prepareStatement(sql); pstm.setString(1,fname); return pstm.executeUpdate() > 0; } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally{ try { if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return false; } @Override public Fruit getFruitByFname(String fname) { try { //加载驱动 Class.forName(DRIVER); //数据库管理器,连接数据库 connection = DriverManager.getConnection(URL, USER, PSW); //sql语句 String sql = "select * from t_fruit where fname = ? "; //预处理对象 pstm = connection.prepareStatement(sql); pstm.setString(1,fname); //执行查询,返回结果集 rs = pstm.executeQuery(); while(rs.next()){ int fid = rs.getInt("fid"); int price = rs.getInt("price"); int fcount = rs.getInt("fcount"); String remark = rs.getString("remark"); Fruit fruit = new Fruit(fid,fname,price,fcount,remark); return fruit; } } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ try { if(rs != null) rs.close(); if(pstm != null) pstm.close(); if(connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } return null; } }
到这里,接口实现类FruitDAOImpl的功能实现就完成啦…
接下来就是对菜单类Menu的功能实现,再完成菜单类的功能代码,我们的水果库存系统功能就可以说是完成了。之后就可以进入代码优化阶段…