• 使用 jdbc 技术升级水果库存系统(后端最终版本,不包含前端)


     1、配置依赖

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.projectlombokgroupId>
    4. <artifactId>lombokartifactId>
    5. <version>1.18.10version>
    6. dependency>
    7. <dependency>
    8. <groupId>junitgroupId>
    9. <artifactId>junitartifactId>
    10. <version>4.12version>
    11. <scope>testscope>
    12. dependency>
    13. <dependency>
    14. <groupId>mysqlgroupId>
    15. <artifactId>mysql-connector-javaartifactId>
    16. <version>8.0.28version>
    17. dependency>
    18. <dependency>
    19. <groupId>com.alibabagroupId>
    20. <artifactId>druidartifactId>
    21. <version>1.2.16version>
    22. dependency>
    23. dependencies>

    2、Fruit 实体类

    1. package com.csdn.fruit.pojo;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Data;
    4. import lombok.NoArgsConstructor;
    5. import java.io.Serializable;
    6. @Data
    7. @NoArgsConstructor
    8. @AllArgsConstructor
    9. public class Fruit implements Serializable {
    10. private Integer fid;
    11. private String fname;
    12. private Integer price;
    13. private Integer fcount;
    14. private String remark;
    15. public Fruit(String fname, Integer price, Integer fcount, String remark) {
    16. this.fname = fname;
    17. this.price = price;
    18. this.fcount = fcount;
    19. this.remark = remark;
    20. }
    21. @Override
    22. public String toString() {
    23. return fname + "\t\t" + price + "\t\t" + fcount + "\t\t" + remark;
    24. }
    25. }

     3、设计数据访问对象层DAO接口

    1. package com.csdn.fruit.dao;
    2. import com.csdn.fruit.pojo.Fruit;
    3. import java.util.List;
    4. //dao :Data Access Object 数据访问对象
    5. //接口设计
    6. public interface FruitDao {
    7. void addFruit(Fruit fruit);
    8. void delFruit(String fname);
    9. void updateFruit(Fruit fruit);
    10. List getFruitList();
    11. Fruit getFruitByFname(String fname);
    12. }

     4、设计DAO层的实现类

    1. package com.csdn.fruit.dao.impl;
    2. import com.csdn.fruit.dao.FruitDao;
    3. import com.csdn.fruit.pojo.Fruit;
    4. import com.csdn.mymvc.dao.BaseDao;
    5. import java.util.List;
    6. public class FruitDaoImpl extends BaseDao implements FruitDao {
    7. @Override
    8. public void addFruit(Fruit fruit) {
    9. String sql = "insert into t_fruit values (0,?,?,?,?)";
    10. super.executeUpdate(sql, fruit.getFname(), fruit.getPrice(), fruit.getFcount(), fruit.getRemark());
    11. }
    12. @Override
    13. public void delFruit(String fname) {
    14. String sql = "delete from t_fruit where fname=?";
    15. super.executeUpdate(sql, fname);
    16. }
    17. @Override
    18. public void updateFruit(Fruit fruit) {
    19. String sql = "update t_fruit set fcount=? where fname = ?";
    20. super.executeUpdate(sql, fruit.getFcount(), fruit.getFname());
    21. }
    22. @Override
    23. public List getFruitList() {
    24. return super.executeQuery("select * from t_fruit");
    25. }
    26. @Override
    27. public Fruit getFruitByFname(String fname) {
    28. return load("select * from t_fruit where fname = ?", fname);
    29. }
    30. }

     5、编写 jdbc 配置文件

    1. jdbc.driver=com.mysql.cj.jdbc.Driver
    2. jdbc.url=jdbc:mysql:///fruitdb
    3. jdbc.user=root
    4. jdbc.pwd=123456
    5. jdbc.init_size=5
    6. jdbc.max_active=20
    7. jdbc.max_wait=3000

    6、 设计数据库操作层(抽象类)

    1. package com.csdn.mymvc.dao;
    2. import com.alibaba.druid.pool.DruidDataSource;
    3. import com.csdn.mymvc.util.ClassUtil;
    4. import javax.sql.DataSource;
    5. import java.io.IOException;
    6. import java.io.InputStream;
    7. import java.lang.reflect.ParameterizedType;
    8. import java.lang.reflect.Type;
    9. import java.sql.*;
    10. import java.util.ArrayList;
    11. import java.util.List;
    12. import java.util.Properties;
    13. public abstract class BaseDao {
    14. private String entityClassName;
    15. public BaseDao() {
    16. // this 是谁? this代表的是 FruitDaoImpl 的实例对象,因为 BaseDao是抽象类,不能直接创建对象,所以 new 的是它的子类对象 FruitDaoImpl
    17. // this.getClass() 获取的是 FruitDaoImpl 的Class对象
    18. // getGenericSuperclass() 获取到的是:BaseDao
    19. // Type 是顶层接口,表示所有的类型。它有一个子接口:ParameterizedType
    20. ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
    21. // Actual:实际的
    22. // getActualTypeArguments() 获取实际的类型参数
    23. Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
    24. Type actualTypeArgument = actualTypeArguments[0];
    25. // System.out.println(actualTypeArgument.getTypeName());//com.csdn.fruit.pojo.Fruit
    26. entityClassName = actualTypeArgument.getTypeName();
    27. initDataSource();
    28. }
    29. private DataSource dataSource;
    30. //加载jdbc.properties文件
    31. private void initDataSource() {
    32. try {
    33. InputStream inputStream = getClass().getClassLoader().getResourceAsStream("jdbc.properties");
    34. Properties properties = new Properties();
    35. properties.load(inputStream);
    36. String driver = properties.getProperty("jdbc.driver", "com.mysql.cj.jdbc.Driver");
    37. String url = properties.getProperty("jdbc.url", "jdbc:mysql:///fruitdb");
    38. String user = properties.getProperty("jdbc.user", "root");
    39. String pwd = properties.getProperty("jdbc.pwd", "123456");
    40. Integer initSize = Integer.parseInt(properties.getProperty("jdbc.init_size", "5"));
    41. Integer maxActive = Integer.parseInt(properties.getProperty("jdbc.max_active", "10"));
    42. Integer maxWait = Integer.parseInt(properties.getProperty("jdbc.max_wait", "5000"));
    43. DruidDataSource druidDataSource = new DruidDataSource();
    44. druidDataSource.setDriverClassName(driver);
    45. druidDataSource.setUrl(url);
    46. druidDataSource.setUsername(user);
    47. druidDataSource.setPassword(pwd);
    48. druidDataSource.setInitialSize(initSize);
    49. druidDataSource.setMaxActive(maxActive);
    50. druidDataSource.setMaxWait(maxWait);
    51. dataSource = druidDataSource;
    52. } catch (IOException e) {
    53. throw new RuntimeException(e);
    54. }
    55. }
    56. private Connection getConn() throws SQLException {
    57. return dataSource.getConnection();
    58. }
    59. private void close(Connection conn, PreparedStatement psmt, ResultSet rs) {
    60. try {
    61. if (rs != null) {
    62. rs.close();
    63. }
    64. if (psmt != null) {
    65. psmt.close();
    66. }
    67. if (conn != null && !conn.isClosed()) {
    68. conn.close();
    69. }
    70. } catch (SQLException e) {
    71. throw new RuntimeException(e);
    72. }
    73. }
    74. //抽取执行更新方法
    75. //执行更新,返回影响行数
    76. //如果是执行 insert,那么可以尝试返回自增列的值
    77. protected int executeUpdate(String sql, Object... params) {
    78. boolean insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
    79. Connection conn = null;
    80. PreparedStatement psmt = null;
    81. try {
    82. conn = getConn();
    83. psmt = insertFlag ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
    84. setParams(psmt, params);
    85. int count = psmt.executeUpdate();
    86. if (insertFlag) {
    87. ResultSet rs = psmt.getGeneratedKeys();
    88. if (rs.next()) {
    89. Long id = rs.getLong(1);
    90. count = id.intValue();
    91. }
    92. }
    93. return count;
    94. } catch (SQLException e) {
    95. throw new RuntimeException(e);
    96. } finally {
    97. close(conn, psmt, null);
    98. }
    99. }
    100. //设置参数
    101. private void setParams(PreparedStatement psmt, Object... params) throws SQLException {
    102. if (params != null && params.length > 0) {
    103. for (int i = 0; i < params.length; i++) {
    104. psmt.setObject(i + 1, params[i]);
    105. }
    106. }
    107. }
    108. //执行查询,返回集合
    109. protected List executeQuery(String sql, Object... params) {
    110. List list = new ArrayList<>();
    111. Connection conn = null;
    112. PreparedStatement psmt = null;
    113. ResultSet rs = null;
    114. try {
    115. conn = getConn();
    116. psmt = conn.prepareStatement(sql);
    117. setParams(psmt, params);
    118. rs = psmt.executeQuery();
    119. ResultSetMetaData rsmd = rs.getMetaData();//元数据,结果集的结构数据
    120. while (rs.next()) {
    121. //T t = new T(); T仅仅是一个符号,所以不能 new
    122. T t = (T) ClassUtil.createInstance(entityClassName);
    123. int columnCount = rsmd.getColumnCount();//获取结果集的列的数据
    124. //jdbc中都是从 1 开始,所以要把 i 改成 从 1 开始
    125. for (int i = 1; i <= columnCount; i++) {
    126. //假设循环 5 次,得到 5 个值,应该对应的是一个对象的 5 个属性的值
    127. String columnName = rsmd.getColumnLabel(i);
    128. Object columnValue = rs.getObject(i);
    129. //给 t 这个对象的 columnName 属性赋 columnValue 值
    130. ClassUtil.setProperty(t, columnName, columnValue);
    131. }
    132. list.add(t);
    133. }
    134. return list;
    135. } catch (SQLException e) {
    136. throw new RuntimeException(e);
    137. } finally {
    138. close(conn, psmt, rs);
    139. }
    140. }
    141. protected T load(String sql, Object... params) {
    142. Connection conn = null;
    143. PreparedStatement psmt = null;
    144. ResultSet rs = null;
    145. try {
    146. conn = getConn();
    147. psmt = conn.prepareStatement(sql);
    148. setParams(psmt, params);
    149. rs = psmt.executeQuery();
    150. ResultSetMetaData rsmd = rs.getMetaData();//元数据,结果集的结构数据
    151. if (rs.next()) {
    152. //T t = new T(); T仅仅是一个符号,所以不能 new
    153. T t = (T) ClassUtil.createInstance(entityClassName);
    154. int columnCount = rsmd.getColumnCount();//获取结果集的列的数据
    155. //jdbc中都是从 1 开始,所以要把 i 改成 从 1 开始
    156. for (int i = 1; i <= columnCount; i++) {
    157. //假设循环 5 次,得到 5 个值,应该对应的是一个对象的 5 个属性的值
    158. String columnName = rsmd.getColumnLabel(i);
    159. Object columnValue = rs.getObject(i);
    160. //给 t 这个对象的 columnName 属性赋 columnValue 值
    161. ClassUtil.setProperty(t, columnName, columnValue);
    162. }
    163. return t;
    164. }
    165. } catch (SQLException e) {
    166. throw new RuntimeException(e);
    167. } finally {
    168. close(conn, psmt, rs);
    169. }
    170. return null;
    171. }
    172. //select max(age) as max_age , avg(age) as avg_age from t_user
    173. // 28 24.5
    174. //select deptNo,avg(sal) as avg_sal from emp group by deptNo
    175. /**
    176. * d001 3500
    177. * d002 3650
    178. * d003 2998
    179. */
    180. protected List executeComplexQuery(String sql, Object... params) {
    181. List list = new ArrayList<>();
    182. Connection conn = null;
    183. PreparedStatement psmt = null;
    184. ResultSet rs = null;
    185. try {
    186. conn = getConn();
    187. psmt = conn.prepareStatement(sql);
    188. setParams(psmt, params);
    189. rs = psmt.executeQuery();
    190. ResultSetMetaData rsmd = rs.getMetaData();//元数据,结果集的结构数据
    191. while (rs.next()) {
    192. int columnCount = rsmd.getColumnCount();//获取结果集的列的数据
    193. Object[] arr = new Object[columnCount];
    194. //jdbc中都是从 1 开始,所以要把 i 改成 从 1 开始
    195. for (int i = 1; i <= columnCount; i++) {
    196. Object columnValue = rs.getObject(i);
    197. //数组从 0 开始,所以要减 1
    198. arr[i - 1] = columnValue;
    199. }
    200. list.add(arr);
    201. }
    202. return list;
    203. } catch (SQLException e) {
    204. throw new RuntimeException(e);
    205. } finally {
    206. close(conn, psmt, rs);
    207. }
    208. }
    209. }

    7、 设计Class工具类

    1. package com.csdn.mymvc.util;
    2. import java.lang.reflect.Field;
    3. import java.lang.reflect.InvocationTargetException;
    4. public class ClassUtil {
    5. public static Object createInstance(String entityClassName) {
    6. try {
    7. return Class.forName(entityClassName).getDeclaredConstructor().newInstance();
    8. } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException |
    9. ClassNotFoundException e) {
    10. throw new RuntimeException(e);
    11. }
    12. }
    13. public static void setProperty(Object instance, String propertyName, Object propertyValue) {
    14. Class aClass = instance.getClass();
    15. try {
    16. Field field = aClass.getDeclaredField(propertyName);
    17. field.setAccessible(true);
    18. field.set(instance, propertyValue);
    19. } catch (NoSuchFieldException | IllegalAccessException e) {
    20. throw new RuntimeException(e);
    21. }
    22. }
    23. }

     8、测试DAO层实现类

    1. package com.csdn.dao.impl;
    2. import com.csdn.fruit.dao.FruitDao;
    3. import com.csdn.fruit.dao.impl.FruitDaoImpl;
    4. import com.csdn.fruit.pojo.Fruit;
    5. import org.junit.Test;
    6. import java.util.List;
    7. public class FruitDaoImplTest {
    8. private FruitDao fruitDao = new FruitDaoImpl();
    9. @Test
    10. public void testAddFruit() {
    11. Fruit fruit = new Fruit("香蕉", 7, 77, "波罗蜜是一种神奇的水果!");
    12. fruitDao.addFruit(fruit);
    13. }
    14. @Test
    15. public void testDelFruit() {
    16. fruitDao.delFruit("哈密瓜");
    17. }
    18. @Test
    19. public void testUpdateFruit() {
    20. Fruit fruit = new Fruit("波罗蜜", 5, 1000, "好吃");
    21. fruitDao.updateFruit(fruit);
    22. }
    23. @Test
    24. public void testGetFruitList() {
    25. List fruitList = fruitDao.getFruitList();
    26. fruitList.stream().forEach(System.out::println);
    27. }
    28. @Test
    29. public void testGetFruitByFname() {
    30. Fruit fruit = fruitDao.getFruitByFname("波罗蜜");
    31. System.out.println(fruit);
    32. }
    33. /*
    34. // this 是谁? this代表的是 FruitDaoImpl 的实例对象,因为 BaseDao是抽象类,不能直接创建对象,所以 new 的是它的子类对象 FruitDaoImpl
    35. // this.getClass() 获取的是 FruitDaoImpl 的Class对象
    36. // getGenericSuperclass() 获取到的是:BaseDao
    37. // Type 是顶层接口,表示所有的类型。它有一个子接口:ParameterizedType
    38. ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
    39. // Actual:实际的
    40. // getActualTypeArguments() 获取实际的类型参数
    41. Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
    42. Type actualTypeArgument = actualTypeArguments[0];
    43. // System.out.println(actualTypeArgument.getTypeName());//com.csdn.fruit.pojo.Fruit
    44. entityClassName = actualTypeArgument.getTypeName();
    45. loadJdbcProperties();
    46. */
    47. @Test
    48. public void testActualTypeArgument() {
    49. //这个方法是用来测试 actualTypeArgument 实际返回的参数
    50. }
    51. }

     9、设计控制台操作菜单

    1. package com.csdn.fruit.view;
    2. import com.csdn.fruit.dao.FruitDao;
    3. import com.csdn.fruit.dao.impl.FruitDaoImpl;
    4. import com.csdn.fruit.pojo.Fruit;
    5. import java.util.List;
    6. import java.util.Scanner;
    7. public class Menu {
    8. Scanner input = new Scanner(System.in);
    9. private FruitDao fruitDao = new FruitDaoImpl();
    10. //显示主菜单
    11. public int showMainMenu() {
    12. System.out.println("================欢迎使用水果库存系统===================");
    13. System.out.println("1.显示库存列表");
    14. System.out.println("2.添加库存记录");
    15. System.out.println("3.查看特定库存");
    16. System.out.println("4.水果下架");
    17. System.out.println("5.退出");
    18. System.out.println("====================================================");
    19. System.out.print("请选择:");
    20. return input.nextInt();
    21. }
    22. //显示库存列表
    23. public void showFruitList() {
    24. List fruitList = fruitDao.getFruitList();
    25. System.out.println("----------------------------------------------------");
    26. System.out.println("名称\t\t单价\t\t库存\t\t备注");
    27. if (fruitList == null || fruitList.size() <= 0) {
    28. System.out.println("对不起,库存为空!");
    29. } else {
    30. /* fruitList.forEach(new Consumer() {
    31. @Override
    32. public void accept(Fruit fruit) {
    33. System.out.println(fruit);
    34. }
    35. });*/
    36. //fruitList.forEach(fruit -> System.out.println(fruit));
    37. fruitList.forEach(System.out::println);
    38. }
    39. System.out.println("----------------------------------------------------");
    40. }
    41. //添加库存记录
    42. public void addFruit() {
    43. System.out.print("请输入水果名称:");
    44. String fname = input.next();
    45. Fruit fruit = fruitDao.getFruitByFname(fname);
    46. if (fruit == null) {
    47. System.out.print("请输入水果单价:");
    48. Integer price = input.nextInt();
    49. System.out.print("请输入水果库存:");
    50. Integer fcount = input.nextInt();
    51. System.out.print("请输入水果备注:");
    52. String remark = input.next();
    53. fruit = new Fruit(fname, price, fcount, remark);
    54. fruitDao.addFruit(fruit);
    55. } else {
    56. System.out.print("请输入追加的库存量:");
    57. Integer fcount = input.nextInt();
    58. fruit.setFcount(fruit.getFcount() + fcount);
    59. fruitDao.updateFruit(fruit);
    60. }
    61. System.out.println("添加成功!");
    62. }
    63. //查看特定库存记录
    64. public void showFruitInfo() {
    65. System.out.print("请输入水果名称:");
    66. String fname = input.next();
    67. Fruit fruit = fruitDao.getFruitByFname(fname);
    68. if (fruit == null) {
    69. System.out.println("对不起,没有找到对应的库存记录!");
    70. } else {
    71. System.out.println("----------------------------------------------------");
    72. System.out.println("名称\t\t单价\t\t库存\t\t备注");
    73. System.out.println(fruit);
    74. System.out.println("----------------------------------------------------");
    75. }
    76. }
    77. //水果下架
    78. public void delFruit() {
    79. System.out.print("请输入水果名称:");
    80. String fname = input.next();
    81. Fruit fruit = fruitDao.getFruitByFname(fname);
    82. if (fruit == null) {
    83. System.out.println("对不起,没有找到需要下架的库存记录!");
    84. } else {
    85. System.out.print("是否确认下架?(Y/N)");
    86. String confirm = input.next();
    87. if ("y".equalsIgnoreCase(confirm)) {
    88. fruitDao.delFruit(fname);
    89. }
    90. }
    91. }
    92. //退出
    93. public boolean exit() {
    94. System.out.print("是否确认退出?(Y/N)");
    95. String confirm = input.next();
    96. boolean flag= !"y".equalsIgnoreCase(confirm);
    97. return flag;
    98. }
    99. }

     10、设计客户端

    1. package com.csdn.fruit.view;
    2. public class Client {
    3. public static void main(String[] args) {
    4. Menu m = new Menu();
    5. boolean flag = true;
    6. while (flag) {
    7. int slt = m.showMainMenu();
    8. switch (slt) {
    9. case 1:
    10. m.showFruitList();
    11. break;
    12. case 2:
    13. m.addFruit();
    14. break;
    15. case 3:
    16. m.showFruitInfo();
    17. break;
    18. case 4:
    19. m.delFruit();
    20. break;
    21. case 5:
    22. //方法设计时是否需要返回值,依据是:是否在调用的地方需要留下一些值用于再运算
    23. flag = m.exit();
    24. break;
    25. default:
    26. System.out.println("你不按套路出牌!");
    27. break;
    28. }
    29. }
    30. System.out.println("谢谢使用!再见!");
    31. }
    32. }

     

  • 相关阅读:
    个人博客测试报告
    3.深入理解Java并发编程
    【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 机器人搬砖(100分) - 三语言AC题解(Python/Java/Cpp)
    Unity学习03:Scene 视图
    1119 Pre- and Post-order Traversals
    云原生中间件RocketMQ(三)RocketMQ集群(多Master和多Master-Slave方式)部署实操
    基于串行并行ADMM算法的主从配电网分布式优化控制研究(Matlab代码实现)
    揭秘GES超大规模图计算引擎HyG:图切分
    免费word转换pdf的软件
    科技云报道:防患于未然,云安全要像空气和水一样无处不在
  • 原文地址:https://blog.csdn.net/m0_65152767/article/details/134082847