基于javaGUI的书店管理系统小项目

版权声明:本文为博主原创,未经同意不得转载 https://blog.csdn.net/weixin_42950079/article/details/88533082

这是一个基于Java GUI的简单的水果管理系统,内容比较简单,主要目的是用于了解JDBC的多层开发模式
该swing项目的除了登陆界面外,还包含4个界面,分别为书籍管理界面,借书记录界面,旧书回收界面和收支帐单界面,它们与工具栏的按钮相互对应。其中除了书籍管理界面的功能( 即:图书的增删改查功能 )实现了之外,其他三个界面都只是假设,还没有任何实现。但这没有关系,书籍管理界面的实现也足够让我们初步认识JDBC的多层开发模式了。

效果图
CD4356
如果有时间有兴趣的朋友可以进行完善补充


项目结构
在这里插入图片描述

创建数据库环境
创建bookMS数据库,再创建好的数据库bookMS中,创建数据库表book,并插入三条数据

/*
SQLyog Ultimate v12.09 (64 bit)
MySQL - 5.5.53 
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;

create table `book` (
	`id` varchar (30),
	`name` varchar (60),
	`price` double ,
	`number` int (11)
); 
insert into `book` (`id`, `name`, `price`, `number`) values('101','红楼梦','82','3');
insert into `book` (`id`, `name`, `price`, `number`) values('102','西游记','63','20');
insert into `book` (`id`, `name`, `price`, `number`) values('103','水浒传','95.8','15');


创建项目,并导入数据库驱动jar包
创建一个普通的java项目,然后创建一个src的同级目录lib(我这里已经创建好了),将MySQL驱动jar包(mysql-connector-java-8.0.11.jar)复制到lib文件夹中
CD4356
选中mysql-connector-java-8.0.11.jar,右键,选择Add as Library,将jar包发布到类路径中
CD4356

在src目录下创建util包,在util包中创建GUIUtil工具类,该工具类主要定义JFrame窗体的标题图标

package util;

import javax.swing.*;
import java.awt.*;
import java.io.File;

public class GUIUtil {

    //给按钮设置图标和文本以及提示文字
    public static void setImageIcon(JButton b, String imgFolder, String tip) {
        //获取图标对象
        ImageIcon icon = new ImageIcon(new File(imgFolder).getAbsolutePath());
        //将图标添加到按钮中
        b.setIcon(icon);
        //设置图片按钮文本
        b.setText(tip);
        //设置图片按钮大小
        b.setPreferredSize(new Dimension(51, 56));
        //设置鼠标停留时显示提示信息
        b.setToolTipText(tip);
        //设置文本在图标下方
        b.setVerticalTextPosition(JButton.BOTTOM);
        //设置文本与图标居中对齐
        b.setHorizontalTextPosition(JButton.CENTER);
    }

}

在src目录下创建view包,在view包中创建Welcome登陆窗口类,在登陆成功后就会跳转到图书管理主界面

package view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public abstract class Welcome extends JFrame {

    ImageIcon img=new ImageIcon("img/CD4356.jpg");
    private JLabel imglabel=new JLabel(img);

    JPanel btnPanel=new JPanel();
    private JLabel usernamelabel=new JLabel("账号:");
    private JTextField username=new JTextField(8);
    private JLabel userpasslabel=new JLabel("密码:");
    private JTextField userpass=new JTextField(8);
    private JButton btn=new JButton("登陆");
    private JLabel report=new JLabel();

    public Welcome(){
        this.init();
        this.addComponent();
        this.addListener();
    }

    // 初始化窗口
    private void init(){
        this.setTitle("学而乐书店");
        this.setSize(600,410);

        // 设置窗口标题图标
        Toolkit toolkit=Toolkit.getDefaultToolkit();
        Image icon = toolkit.getImage("img/titleIcon.jpg");
        this.setIconImage(icon);

        // 设置窗口再显示器居中显示,还可以使用this.setLayout(null);方式设置窗口居中
        Dimension screenSize =toolkit.getScreenSize();
        int x=(screenSize.width-this.getWidth())/2;
        int y=(screenSize.height-this.getHeight())/2;
        this.setLocation(x,y);

        // 设置窗口大小不可变
        this.setResizable(false);
        // 设置单击窗口右上角×时,默认为结束项目运行
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    // 为窗口添加组件
    private void addComponent() {
        imglabel.setBounds(0,0,img.getIconWidth(),img.getIconHeight());
        this.add(imglabel,BorderLayout.NORTH);

        btnPanel.setLayout(null);
        usernamelabel.setBounds(40,17,50,28);
        usernamelabel.setFont(new Font("隶书", Font.PLAIN, 20));
        username.setBounds(100,17,150,28);
        userpasslabel.setBounds(265,17,50,28);
        userpasslabel.setFont(new Font("隶书", Font.PLAIN, 20));
        userpass.setBounds(325,17,150,28);
        btn.setBackground(Color.lightGray);
        btn.setBounds(500,16,60,30);
        btnPanel.add(usernamelabel);
        btnPanel.add(username);
        btnPanel.add(userpasslabel);
        btnPanel.add(userpass);
        btnPanel.add(btn);

        report.setBounds(200,50,200,20);

        report.setFont(new Font("隶书", Font.PLAIN, 20));
        report.setText("账号密码默认为123!");
        report.setForeground(Color.red);
        btnPanel.add(report);
        this.add(btnPanel);
    }

    // 为按钮设置监听器
    private void addListener() {
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(username.getText().equals("123") && userpass.getText().equals("123")){
                    showBookAdmin();
                    // 进入JDialog管理界面后,关闭JFrame窗口
                    dispose();
                }else{
                    report.setText("账号或密码错误!");
                    username.setText("");
                    userpass.setText("");
                }
            }
        });
    }

    public abstract void showBookAdmin();

}

在view包中创建BookAdmin图书管理界面类

package view;

import util.GUIUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public abstract class BookAdmin extends JFrame {

    public JToolBar toolBar=new JToolBar();
    JButton adminBtn=new JButton();
    JButton lendBtn=new JButton();
    JButton recycleBtn=new JButton();
    JButton billBtn=new JButton();

    private JLabel tableName=new JLabel("图书列表");

    public JScrollPane tablePane=new JScrollPane();
    public JTable table=new JTable();

    private JLabel idLabel=new JLabel("图书编号");
    private JLabel nameLabel=new JLabel("图书名称");
    private JLabel priceLabel=new JLabel("图书单价");
    private JLabel numberLabel=new JLabel("图书余量");

    public JTextField addIdText=new JTextField(6);
    public JTextField addNameText=new JTextField(6);
    public JTextField addPriceText=new JTextField(6);
    public JTextField addNumberText=new JTextField(6);
    private JButton addBtn=new JButton("新增图书");

    public JTextField updateIdText=new JTextField(6);
    public JTextField updateNameText=new JTextField(6);
    public JTextField updatePriceText=new JTextField(6);
    public JTextField updateNumberText=new JTextField(6);
    private JButton updateBtn=new JButton("修改图书");

    public JTextField delIdText=new JTextField(6);
    private JButton delBtn=new JButton("删除图书");


    public BookAdmin() {
        this.init();
        this.addComponent();
        this.addListener();
    }

    // 初始化窗口
    private void init() {
        this.setTitle("学而乐书店");

        Toolkit toolkit=Toolkit.getDefaultToolkit();
        Image icon = toolkit.getImage("img/titleIcon.jpg");
        this.setIconImage(icon);

        this.setSize(600,450);
        // 设置窗口大小不可变
        this.setResizable(false);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    }

    // 为窗口添加组件
    private void addComponent() {
        //通过GUIUtil类的setImageIcon()方法来设置图片按钮,并传入按钮对象,图片名和鼠标停留的提示信息
        GUIUtil.setImageIcon(adminBtn,"img/book.jpg","书籍管理");
        GUIUtil.setImageIcon(lendBtn,"img/lend.jpg","借书记录");
        GUIUtil.setImageIcon(recycleBtn,"img/recycle.jpg","旧书回收");
        GUIUtil.setImageIcon(billBtn,"img/bill.jpg","收支账单");
        //将按钮添加到工具栏
        toolBar.add(adminBtn);
        toolBar.add(lendBtn);
        toolBar.add(recycleBtn);
        toolBar.add(billBtn);
        //setBounds()方法设置组件位置,使用该方法要setLayout(null)清空布局管理器
        toolBar.setBounds(20,0,560,65);
        this.add(toolBar, BorderLayout.NORTH);
        //设置工具栏是否可以移动
        toolBar.setFloatable(true);

        this.setLayout(null);

        tableName.setBounds(250,80,100,25);
        // 设置字体样式
        tableName.setFont(new Font("华文隶书", Font.PLAIN, 23));
        tableName.setForeground(Color.BLACK.brighter());
        this.add(tableName);

        table.getTableHeader().setReorderingAllowed(false);
        table.getTableHeader().setResizingAllowed(false);
        table.setEnabled(false);
        // 使用setBounds()设置组件位置,但使用之前必须setLayout(null)清空布局管理器

        tablePane.setBounds(50,110,500,170);
        tablePane.setViewportView(table);
        this.add(tablePane);

        idLabel.setBounds(50,290,70,25);
        nameLabel.setBounds(150,290,70,25);
        priceLabel.setBounds(250,290,70,25);
        numberLabel.setBounds(350,290,70,25);
        idLabel.setFont(new Font("隶书", Font.PLAIN, 17));
        nameLabel.setFont(new Font("隶书", Font.PLAIN, 17));
        priceLabel.setFont(new Font("隶书", Font.PLAIN, 17));
        numberLabel.setFont(new Font("隶书", Font.PLAIN, 17));
        this.add(idLabel);
        this.add(nameLabel);
        this.add(priceLabel);
        this.add(numberLabel);


        addIdText.setBounds(50,320,80,25);
        addNameText.setBounds(150,320,80,25);
        addPriceText.setBounds(250,320,80,25);
        addNumberText.setBounds(350,320,80,25);
        addBtn.setBounds(450,320,100,25);
        this.add(addIdText);
        this.add(addNameText);
        this.add(addPriceText);
        this.add(addNumberText);
        addBtn.setBackground(Color.lightGray);
        addBtn.setFont(new Font("隶书", Font.PLAIN, 16));
        this.add(addBtn);


        updateIdText.setBounds(50,350,80,25);
        updateNameText.setBounds(150,350,80,25);
        updatePriceText.setBounds(250,350,80,25);
        updateNumberText.setBounds(350,350,80,25);
        updateBtn.setBounds(450,350,100,25);
        this.add(updateIdText);
        this.add(updateNameText);
        this.add(updatePriceText);
        this.add(updateNumberText);
        updateBtn.setBackground(Color.lightGray);
        updateBtn.setFont(new Font("隶书", Font.PLAIN, 16));
        this.add(updateBtn);


        delIdText.setBounds(50,380,80,25);
        delBtn.setBounds(450,380,100,25);
        this.add(delIdText);
        delBtn.setBackground(Color.lightGray);
        delBtn.setFont(new Font("隶书", Font.PLAIN, 16));
        this.add(delBtn);

    }

    // 为按钮添加监听器
    private void addListener(){
        addBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                addBook();
            }
        });
        updateBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                updateBook();
            }
        });
        delBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                deleteBook();
            }
        });
    }

    //查询方法
    public abstract void queryAll();

    //添加方法
    public abstract void addBook();

    //修改方法
    public abstract void updateBook();

    //删除方法
    public abstract void deleteBook();

}

在src下创建entity包,在包中创建Book实体类

package entiry;

public class Book {

    private String id;
    private String name;
    private Double price;
    private int number;

    public Book() {

    }

    public Book(String id, String name, Double price, int number) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.number = number;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

}

在util包下创建DBUtil数据连接辅助类
由于在传统的JDBC中,即使用户执行一条最简单的数据查询操作,都必须执行如下过程:获取连接→创建Statement→执行数据操作→获取结果→关闭Statement→关闭结果集→关闭连接,除此之外还需进行许多异常处理的操作
而在传统的JDBC中,虽然无法做到像Spring JDBC框架那样将可复用的样板式代码都进行隔离封装,更无法hibernate、mybatis框架那样简便,但像获取连接、关闭Statement、关闭结果集、关闭连接这部分的代码还是可以独立出来的,做到部分代码的复用

package util;

import java.sql.*;

public class DBUtil {

    private static final String driverClass="com.mysql.cj.jdbc.Driver";
    private static final String Url="jdbc:mysql://localhost:3306/bookMS?serverTimezone=GMT%2B8";
    private static final String usename="root";
    private static final String usepass="root";

    /**
     * 创建数据库连接
     * @returns
     */
    public static Connection getConnection(){
        Connection conn=null;
        try {
            Class.forName(driverClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            conn= DriverManager.getConnection(Url,usename,usepass);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭连接,释放资源
     * 执行查询操作的方法中使用
     * @param conn
     */
    public static void close(ResultSet rs, Statement stmt,Connection conn){
        try{
            if(rs!=null){
                rs.close();
            }
            if(stmt!=null){
                stmt.close();
            }
            if(conn!=null||!conn.isClosed()){
                conn.close();
            }
        }catch (SQLException e){
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接,释放资源
     * 执行增删改操作的方法中使用
     * @param conn
     */
    public static void close(Statement stmt,Connection conn){
        try{
            if(stmt!=null){
                stmt.close();
            }
            if(conn!=null||!conn.isClosed()){
                conn.close();
            }
        }catch (SQLException e){
            e.printStackTrace();
        }
    }

}

在src目录下创建dao包(存放持久层的代码),在包中创建BookDao操作类

package dao;

import entiry.Book;
import util.DBUtil;

import java.sql.*;
import java.util.ArrayList;

/**
 * Dao数据访问层
 *
 * 主要是对数据进行增删改查操作的层,也称持久层
 */
public class BookDao {

    /**
     * queryAll()方法
     * 查询所有图书信息,返回一个集合
     * @return
     */
    public ArrayList<Book> queryAll(){
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        ArrayList<Book> list=new ArrayList<>();
        try{
            conn= DBUtil.getConnection();
            stmt=conn.createStatement();
            String sql="select*from book order by id";
            rs=stmt.executeQuery(sql);
            while(rs.next()){
                Book book=new Book();
                // 将获取结果集的信息封装到Book实体类中
                book.setId(rs.getString("id"));
                book.setName(rs.getString("name"));
                book.setPrice(rs.getDouble("price"));
                book.setNumber(rs.getInt("number"));
                // 将实体类中的信息封装到集合中
                list.add(book);
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            DBUtil.close(rs,stmt,conn);
        }
        return list;
    }

    /**
     * addBook()方法
     * 以实体类Book作为参数类型,实参封装了装备添加到数据库中的图书信息
     *
     * 使用PreparedStatement对象执行插入操作,防止SQL语句注入
     * @return
     */
    public void addBook(Book book){
        Connection conn=null;
        PreparedStatement prestmt=null;
        try{
            conn=DBUtil.getConnection();
            String sql="insert into book(id,name,price,number)values(?,?,?,?)";
            prestmt=conn.prepareStatement(sql);
            prestmt.setString(1,book.getId());
            prestmt.setString(2,book.getName());
            prestmt.setDouble(3,book.getPrice());
            prestmt.setInt(4,book.getNumber());
            int num=prestmt.executeUpdate();
            if(num>0){
                System.out.println("插入数据成功!");
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            DBUtil.close(prestmt,conn);
        }
    }

    /**
     * deleteBook方法
     * 删除记录deleteBook()方法中的形参类型为String类型的id,也可改为实体类Book作为形参类型
     *
     * 使用PreparedStatement对象执行删除操作,防止SQL语句注入
     * @return
     */
    public void deleteBook(String id){
        Connection conn=null;
        PreparedStatement prestmt=null;
        try{
            conn=DBUtil.getConnection();
            String sql="delete from book where id=?";
            prestmt=conn.prepareStatement(sql);
            prestmt.setString(1,id);
            int num=prestmt.executeUpdate();
            if(num>0){
                System.out.println("删除数据成功!");
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            DBUtil.close(prestmt,conn);
        }
    }

}

在src目录下创建service包(存放业务逻辑层的代码),在包中创建BookService业务逻辑类,即服务类的代码

package service;

import dao.BookDao;
import entiry.Book;

import java.util.ArrayList;

/**
 * Service业务逻辑层
 *
 * 主要是调用Dao数据访问层的基本数据操作来完成业务逻辑处理
 */
public class BookService {

    // 创建AdminDao实例化对象
    private BookDao bookDao=new BookDao();

    // 实现查询逻辑处理
    public ArrayList<Book> queryAll(){
        ArrayList data=bookDao.queryAll();
        return data;
    }

    // 实现添加逻辑处理
    public boolean addBook(String id, String name, double price, int number){
        // 遍历数据,判断要插入的水果编号是否存在
        ArrayList<Book> data=queryAll();
        for(int i=0;i<data.size();i++){
            Book book=data.get(i);
            if(id.equals(book.getId())){
                return false;
            }
        }
        Book thisbook=new Book(id,name,price,number);
        bookDao.addBook(thisbook);
        return true;
    }

    /**
     * BookDao中没有定义修改操作的方法,我们这个小项目中不是通过执行修改SQL语句来实现数据修改的,
     * 而是通过删除要修改的数据后,再添加新的数据的方式来实现数据修改的
     * @return
     */
    public boolean updateBook(String id, String name, double price, int number) {
        // 遍历数据,判断要插入的水果编号是否存在
        ArrayList<Book> data=queryAll();
        for(int i=0;i<data.size();i++){
            Book book=data.get(i);
            if(id.equals(book.getId())){
                // 如果该图书存在则删除
                bookDao.deleteBook(id);
                // 添加修改内容作为新的图书内容
                Book thisbook=new Book(id,name,price,number);
                bookDao.addBook(thisbook);
                /**
                 * 这里不要使用BookService类中的deleteBook()和addBook()方法来删除添加图书,
                 * 因为这两个方法都要遍历一次数据,如果数据量很大的话就会消耗很多时间,
                 * 所以应如上面三行代码这样,直接调用BookDao类中的方法来实现图书的删除添加
                 */
//                deleteBook(id);
//                addBook(id,name,price,number);
                return true;
            }
        }
        return false;
    }

    public boolean deleteBook(String id) {
        // 遍历数据,判断要插入的水果编号是否存在
        ArrayList<Book> data=queryAll();
        for(int i=0;i<data.size();i++){
            Book book=data.get(i);
            if(id.equals(book.getId())){
                bookDao.deleteBook(id);
                return true;
            }
        }
        return false;
    }
    
}

在src目录下创建controller包(存放控制层/表现层的代码),在包中创建BookController控制类的代码

package controller;

import entiry.Book;
import service.BookService;
import view.BookAdmin;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.util.ArrayList;

/**
 * BookController表示层
 *
 * 对数据库的访问通过业务逻辑层的方法调用来实现
 */
public class BookController extends BookAdmin {

    // 创建BookService实例化对象
    private BookService bookService=new BookService();

    public BookController() {
        queryAll();
    }

    // 将查询的数据转换成二维数组的格式,作为表格中表体的内容
    private String[][] list2Array(ArrayList<Book> list){
        String[][] body=new String[list.size()][4];
        for(int i=0;i<list.size();i++){
            Book book=list.get(i);
            body[i][0]=book.getId();
            body[i][1]=book.getName();
            // valueOf()方法返回非字符串类型数据的字符串表现形式
            body[i][2]= String.valueOf(book.getPrice());
            body[i][3]= String.valueOf(book.getNumber());
        }
        return body;
    }

    @Override
    public void queryAll() {
        String[] head={"图书编号","图书名称","图书价格","图书余量"};
        // 将queryAll()方法返回的数据封装到集合中
        ArrayList<Book> list=bookService.queryAll();
        // 定义一个String类型的二维数组存储list2Array()方法返回的二维数组,这个二位数组就是表格的表体内容
        String[][] body=list2Array(list);
        TableModel tableModel=new DefaultTableModel(body,head);
        table.setModel(tableModel);
    }

    @Override
    public void addBook() {
        String id=addIdText.getText();
        String name=addNameText.getText();
        String price=addPriceText.getText();
        String number=addNumberText.getText();
        boolean addSuccess=bookService.addBook(id,name,Double.parseDouble(price),Integer.parseInt(number));
        if(addSuccess){
            queryAll();
        }else{
            JOptionPane.showMessageDialog(this,"图书已存在!");
        }
    }

    @Override
    public void updateBook() {
        String id=updateIdText.getText();
        String name=updateNameText.getText();
        String price=updatePriceText.getText();
        String number=updateNumberText.getText();
        boolean updateSuccess=bookService.updateBook(id,name,Double.parseDouble(price),Integer.parseInt(number));
        if(updateSuccess){
            queryAll();
        }else{
            JOptionPane.showMessageDialog(this,"图书不存在!");
        }
    }

    @Override
    public void deleteBook() {
        String id=delIdText.getText();
        boolean deleteSuccess=bookService.deleteBook(id);
        if(deleteSuccess){
            queryAll();
        }else{
            JOptionPane.showMessageDialog(this,"图书不存在!");
        }
    }
    
}

在src目录下创建startup包,在包中创建BooKStart类(main函数所在类),用来启动项目

package startup;

import controller.BookController;
import view.Welcome;

public class BooKStart extends Welcome {

    @Override
    public void showBookAdmin() {
        new BookController().setVisible(true);
    }

    public static void main(String[] args) {
        new BooKStart().setVisible(true);
    }
}


下面图片来源于runoob.com

三层架构
CD4356

三层与实体层之间的依赖关系
CD4356

来自生活中的举例
在这里插入图片描述

两层和三层的区别?
CD4356
CD4356


网盘链接:https://pan.baidu.com/s/1r3SFZCldTz4HTPU0Nzh-gQ
提取码:hzwy

Github地址:https://github.com/CD4356/BookStore

猜你喜欢

转载自blog.csdn.net/weixin_42950079/article/details/88533082