从零到一:Java三层架构下的图书馆管理系统开发指南

引言

使用JavaSE相关知识完成一个以三层架构为设计规范的图书管理系统,不包括前端页面(使用main方法+Scanner()模拟用户输入),目的是为了基于一个项目快速了解三层架构的项目设计规范的实践。

 开发流程

  • 确认需求
  • 导入相关的jar包和JDBCUtils工具类(工具类的目的是为了简化开发)
  • 创建数据库表并准备基础数据
  • 书写对应实体类
  • 先分析功能执行所需的SQL支持,然后书写DAO层
  • 书写DAO的Junit测试类
  • 书写Service层+实现业务需求+事务控制
  • 书写Service的Junit测试类
  • 书写视图层,对接用户接收用户数据,并反馈结果

项目实战

一、确认需求

 需求:想要创建一个图书管理系统,能够对书籍进行新增,修改,删除,查看所有书籍和查看单个书籍等功能,并且需要实现用户注册和登陆功能

项目结构图

导入jar包:

源代码结构图:

二、导入资源

导入相关jar包

        在项目的结构下创建lib包,导入相关的jar包,并右键lib,选择添加为库(目的是为了可以直接使用import导包语句直接使用jar包中的类)

分析:

  • 红色:spring封装JDBC的JDBCTemplate依赖jar包
  • 黄色:mysql驱动jar包(8.0版本)
  • 蓝色:Junit测试驱动jar包

jar包链接:

百度网盘:依赖jar包

阿里网盘:依赖jar包

导入JDBCUtils工具类

package com.csx.util;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class JDBCUtils {
    private static DataSource dataSource =null;

    static{
        try (
                InputStream is=JDBCUtils.class.getResourceAsStream("/JDBCUtils.properties")
        ){
            Properties p = new Properties();
            p.load(is);
            dataSource = new DriverManagerDataSource(p.getProperty("url"), p.getProperty("username"), p.getProperty("password"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static JdbcTemplate getJDBCTemplate(){
        //创建JDBCTemplate对象并传入数据库连接池
        JdbcTemplate template = new JdbcTemplate(dataSource);
        return template;
    }

    /**
     * 获取数据库连接池
     * @return
     */
    public static DataSource getDataSource(){
        return dataSource;
    }

    /**
     * 开始线程绑定 +获取连接
     * @return
     */
    public static Connection startTransaction(){
        if (!TransactionSynchronizationManager.isSynchronizationActive()){
            TransactionSynchronizationManager.initSynchronization();
        }
        Connection connection =DataSourceUtils.getConnection(dataSource);
        try {
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return connection;
    }

    /**
     * 提交事务
     * @param conn
     */
    public static void commit(Connection conn){
        try {
            conn.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            clear(conn);
        }
    }

    /**
     * 回滚事务
     * @param conn
     */
    public static void rollback(Connection conn){
        try {
            conn.rollback();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            clear(conn);
        }
    }


    /**
     * 解除线程绑定+释放资源+归还连接到线程池
     * @param conn
     */
    public static void clear(Connection conn){
        //清除线程绑定的资源
        TransactionSynchronizationManager.clear();
        TransactionSynchronizationManager.unbindResourceIfPossible(dataSource);
        //归还数据库连接至连接池
        if (conn!=null){//非空判断,判断为空再归还
            DataSourceUtils.releaseConnection(conn,dataSource);
        }
    }
}
JDBCUtils.properties文件内容

配置文件放在src目录下,在src的直接子目录下(保存本地的数据库连接url,用户名和密码)

url=jdbc:mysql://localhost:3306/csx_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=Asia/shanghai
username=root
password=root

三、创建数据库表并准备基础数据

数据库名 csx_demo

创建两张表:t_user t_book

创表语句不在赘述,保证user_id,book_id为主键即可,自行添加约束

四、书写实体类

可以参考我的另一篇博客:

设计之道:ORM、DAO、Service与三层架构的规范探索

User:

package com.csx.entity;

import java.io.Serializable;

public class User implements Serializable {
    private Integer userId;
    private String userName;
    private String password;
    public User(){}

    public User(Integer userId, String userName, String password) {
        this.userId = userId;
        this.userName = userName;
        this.password = password;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

Book:

package com.csx.entity;

import java.io.Serializable;

public class Book implements Serializable {
    private Integer bookId;
    private String bookName;
    private String author;
    private Double price;
    private Integer stock;

    @Override
    public String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", bookName='" + bookName + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }

    public Book(){}
    public Book(Integer bookId, String bookName, String author, Double price, Integer stock) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.author = author;
        this.price = price;
        this.stock = stock;
    }

    public Integer getBookId() {
        return bookId;
    }

    public void setBookId(Integer bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Double getPrice() {
        return price;
    }

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

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }
}

五、书写DAO层

分析业务实现需要的SQL支持,例如查询书籍信息需要select的SQL支持,新增数据需要insert的SQL支持等

UserDao:

package com.csx.dao;

import com.csx.entity.User;

public interface UserDao {

    /**
     * 查询根据用户名指定用户是否存在
     * @param userName
     * @return
     */
    public User selectUserByUserName(String userName);

    /**
     * 新增用户信息
     * @param user
     * @return
     */
    public int insertUser(User user);


}

UserDaoImpl:

package com.csx.dao.impl;

import com.csx.dao.UserDao;
import com.csx.entity.User;
import com.csx.util.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

public class UserDaoImpl implements UserDao {
    private JdbcTemplate template = JDBCUtils.getJDBCTemplate();
    /**
     * 查询根据用户名指定用户是否存在
     *
     * @param userName
     * @return
     */
    @Override
    public User selectUserByUserName(String userName) {
        String sql ="select * from t_user where user_name=?";
        List<User> list = template.query(sql, new BeanPropertyRowMapper<>(User.class), userName);
        return list.isEmpty()?null:list.get(0);
    }

    /**
     * 新增用户信息
     *
     * @param user
     * @return
     */
    @Override
    public int insertUser(User user) {
        String sql="insert into t_user(user_name,password) values(?,?)";
        int n = template.update(sql, user.getUserName(), user.getPassword());
        return n;
    }
}

BookDao:

package com.csx.dao;

import com.csx.entity.Book;

import java.util.List;

public interface BookDao {
    /**
     * 查询所有图书信息
     * @return 返回查询到的所有图书信息
     */
    public List<Book> selectBooks();

    /**
     * 根据book_name查询指定图书信息
     * @param booName 图书名
     * @return  指定图书信息
     */
    public Book selectBookByBookName(String booName);

    /**
     * 插入图书信息
     * @return
     */
    public int insertBook(Book book);

    /**
     * 根据图书名删除图书
     * @param bookName
     * @return
     */
    public int deleteBookByBookName(String bookName);
}

BookDaoImpl:

package com.csx.dao.impl;

import com.csx.dao.BookDao;
import com.csx.entity.Book;
import com.csx.util.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

public class BookDaoImpl implements BookDao {
    private JdbcTemplate template = JDBCUtils.getJDBCTemplate();
    /**
     * 查询所有图书信息
     *
     * @return 返回查询到的所有图书信息
     */
    @Override
    public List<Book> selectBooks() {
       String sql="select * from t_book";
        List<Book> list = template.query(sql, new BeanPropertyRowMapper<>(Book.class));
        return list;
    }

    /**
     * 根据book_name查询指定图书信息
     *
     * @param booName 图书名
     * @return 指定图书信息
     */
    @Override
    public Book selectBookByBookName(String booName) {
       String sql="select * from t_book where book_name=?";
        List<Book> list = template.query(sql, new BeanPropertyRowMapper<>(Book.class), booName);
        return list.isEmpty()?null:list.get(0);
    }

    /**
     * 插入图书信息
     *
     * @return
     */
    @Override
    public int insertBook(Book book) {
        String sql="insert into t_book(book_name,author,price,stock) values(?,?,?,?)";
        int n=template.update(sql,book.getBookName(),book.getAuthor(),book.getPrice(),book.getStock());
        return n;
    }

    /**
     * 根据图书名删除图书
     *
     * @param bookName
     * @return
     */
    @Override
    public int deleteBookByBookName(String bookName) {
       String sql="delete from t_book where book_name=?";
        int n = template.update(sql, bookName);
        return n;
    }
}

六、书写DAO层的测试类

实际开发中,测试是很重要的一部分,理论上,我们应该对DAO和Service中所有的方法和功能都进行测试。

 BookDaoImplTest:

package com.csx.test;

import com.csx.dao.BookDao;
import com.csx.dao.impl.BookDaoImpl;
import com.csx.entity.Book;
import org.junit.Test;

import java.util.List;

public class BookDaoImplTest {
    private BookDao bookDao =new BookDaoImpl();

    @Test
    public void selectBooks(){
        List<Book> books = bookDao.selectBooks();
        books.forEach(book -> System.out.println(book));

    }
    @Test
    public void selectBookByBookName(){
        Book book = bookDao.selectBookByBookName("堂吉诃德");
        System.out.println(book);
    }
    @Test
    public void insertBook(){
        Book book =new Book(null,"无敌烽火轮","csx",99.9,20);
        int i = bookDao.insertBook(book);
        if (i==1){
            System.out.println("新增成功");
        }else {
            System.out.println("新增失败");
        }

    }
    @Test
    public void deleteBookByBookName(){
        int i = bookDao.deleteBookByBookName("无敌烽火轮");
        if (i==1){
            System.out.println("删除成功");
        }else {
            System.out.println("删除失败");
        }

    }


}

UserDaoImplTest:

package com.csx.test;

import com.csx.dao.UserDao;
import com.csx.dao.impl.UserDaoImpl;
import com.csx.entity.User;
import org.junit.Test;

public class UserDaoImplTest {
    private UserDao userDao =new UserDaoImpl();

    @Test
    public void selectUserByUserName(){
        User user = userDao.selectUserByUserName("admin");
        System.out.println(user);
    }

    @Test
    public void insertUser(){
        User user =new User(null,"test1","test");
        int n=userDao.insertUser(user);
        System.out.println(n);
    }
}

七、书写Service层

Service层关注代码的功能实现,在这一层不仅要调用DAO的SQL支持完成功能逻辑,还需要关注事务执行的完整性(即事务的安全控制,保证多条SQL执行的完整性)

 UserService:

package com.csx.service;

import com.csx.dao.UserDao;
import com.csx.dao.impl.UserDaoImpl;

public interface UserService {
    /**
     * 注册用户功能
     * @param username  用户传递的用户名
     * @param password  用户传递的密码
     * @return  注册是否成功的boolean结果
     */
   public boolean register(String username,String password);

    /**
     * 用户登录功能
     * @param username  用户传递的用户名
     * @param password  用户传递的密码
     * @return  登录是否成功的boolean结果
     */
   public boolean login(String username,String password);

}

UserServiceImpl:

package com.csx.service.impl;

import com.csx.dao.UserDao;
import com.csx.dao.impl.UserDaoImpl;
import com.csx.entity.User;
import com.csx.service.UserService;
import com.csx.util.JDBCUtils;

import java.sql.Connection;

public class UserServiceImpl implements UserService {
    private UserDao userDao =new UserDaoImpl();

    /**
     * 注册用户功能
     *
     * @param username 用户传递的用户名
     * @param password 用户传递的密码
     * @return 注册是否成功的boolean结果
     */
    @Override
    public boolean register(String username, String password) {
        boolean boo =false;
        Connection conn =null;
        try {
            conn = JDBCUtils.startTransaction();
            //业务功能
            User u = userDao.selectUserByUserName(username);
            if (u == null) {
                User user = new User(null, username, password);
                userDao.insertUser(user);
                boo = true;
            } else {
                throw new RuntimeException("用户名重复,注册失败!");
            }
            JDBCUtils.commit(conn);
        }catch (Exception e){
            JDBCUtils.rollback(conn);
            throw  new RuntimeException(e);
        }
        return boo;
    }

    /**
     * 用户登录功能
     *
     * @param username 用户传递的用户名
     * @param password 用户传递的密码
     * @return 登录是否成功的boolean结果
     */
    @Override
    public boolean login(String username, String password) {
        boolean boo =false;
        Connection conn =null;
        try{
            conn= JDBCUtils.startTransaction();
            //业务功能
        User user = userDao.selectUserByUserName(username);
        //判断用户名是否存在
        if (user!=null){
            //判断密码是否正确
            if (user.getPassword().equals(password)){
                boo=true;
            }else {
                throw new RuntimeException("密码错误!");
            }
        }else {
            throw new RuntimeException("用户不存在!");
        }
        JDBCUtils.commit(conn);
        }catch (Exception e){
            JDBCUtils.rollback(conn);
            throw new RuntimeException(e);
        }
        return boo;

    }
}

BookService:

package com.csx.service;

import com.csx.entity.Book;

import java.util.List;

public interface BookService {
    /**
     * 查询所有图书信息
     * @return
     */
    public List<Book> queryBooks();

    /**
     * 根据图书名查询指定图书信息
     * @param bookName
     * @return
     */
    public Book queryBookByBookName(String bookName);

    /**
     * 插入新的图书信息,图书名不可重复
     * @param book
     * @return
     */
    public boolean addBook(Book book);

    /**
     * 根据图书名删除指定图书信息
     * @param bookName
     * @return
     */

    public boolean removeBookByBookName(String bookName);
}

BookServiceImpl:

package com.csx.service.impl;

import com.csx.dao.BookDao;
import com.csx.dao.impl.BookDaoImpl;
import com.csx.entity.Book;
import com.csx.service.BookService;
import com.csx.util.JDBCUtils;

import java.sql.Connection;
import java.util.List;

public class BookServiceImpl implements BookService {
    private BookDao bookDao =new BookDaoImpl();

    /**
     * 查询所有图书信息
     *
     * @return
     */
    @Override
    public List<Book> queryBooks() {
        return bookDao.selectBooks();
    }

    /**
     * 根据图书名查询指定图书信息
     *
     * @param bookName
     * @return
     */
    @Override
    public Book queryBookByBookName(String bookName) {
        return bookDao.selectBookByBookName(bookName);
    }

    /**
     * 插入新的图书信息,图书名不可重复
     *
     * @param book
     * @return
     */
    @Override
    public boolean addBook(Book book) {
        boolean boo =false;
        Connection conn =null;
        try{
            conn= JDBCUtils.startTransaction();
            //业务功能
            Book b = bookDao.selectBookByBookName(book.getBookName());
            if (b==null){
                bookDao.insertBook(book);
                boo=true;
            }else {
                throw new RuntimeException("图书存在,无法重复添加!");
            }
            JDBCUtils.commit(conn);
        }catch (Exception e){
            JDBCUtils.rollback(conn);
            throw new RuntimeException(e);
        }
        return boo;
    }

    /**
     * 根据图书名删除指定图书信息
     *
     * @param bookName
     * @return
     */
    @Override
    public boolean removeBookByBookName(String bookName) {
        return bookDao.deleteBookByBookName(bookName)==1?true:false;
    }
}

这里主要展示完整的实现流程,至于如何实现事务控制,我会在其他博客中详细说明

 八、书写Service层的测试类

BookServiceImplTest:

package com.csx.test;

import com.csx.entity.Book;
import com.csx.service.BookService;
import com.csx.service.impl.BookServiceImpl;
import org.junit.Test;

import java.util.List;

public class BookServiceImplTest {
    private BookService bookService =new BookServiceImpl();
    @Test
    public  void queryBooks(){
        List<Book> books = bookService.queryBooks();
        books.forEach(book -> System.out.println(book));
    }
    @Test
    public void queryBookByBookName(){
        Book book = bookService.queryBookByBookName("伪君子");
        System.out.println(book);
    }
    @Test
    public void addBook(){
       boolean n= bookService.addBook(new Book(null,"海鲜养殖","海王",22.4,100));
        if (n){
            System.out.println("新增成功");
        }else {
            System.out.println("新增失败");
        }
    }
    @Test
    public void removeBookByBookName(){
        boolean b = bookService.removeBookByBookName("海鲜养殖");
        if (b){
            System.out.println("删除成功");
        }else {
            System.out.println("删除失败");
        }

    }
}

UserServiceImplTest:

package com.csx.test;

import com.csx.service.UserService;
import com.csx.service.impl.UserServiceImpl;
import org.junit.Test;

public class UserServiceImplTest {
    private UserService userService =new UserServiceImpl();

    @Test
    public void register(){
        boolean b = userService.register("root1", "root");
        if (b){
            System.out.println("注册成功");
        }else {
            System.out.println("注册失败");
        }
    }
    @Test
    public  void  login(){
        boolean login = userService.login("root", "123456");
        if (login){
            System.out.println("登录成功");
        }else {
            System.out.println("登录是吧");
        }
    }

}

九、书写视图层

package com.csx.view;

import com.csx.entity.Book;
import com.csx.service.BookService;
import com.csx.service.UserService;
import com.csx.service.impl.BookServiceImpl;
import com.csx.service.impl.UserServiceImpl;

import java.util.List;
import java.util.Scanner;

public class BookManagerView {
    public static void main(String[] args) {
        //用户注册
        Scanner sc =new Scanner(System.in);
        UserService userService =new UserServiceImpl();
        while (true){
            System.out.println("请输入要注册的账户名:");
            String username = sc.next();
            System.out.println("请输入要注册的密码:");
            String password = sc.next();
           try{
                if(userService.register(username,password)) {
                System.out.println("注册成功!");
                break;
            }else {
                System.out.println("注册失败!");
                return;
            }
             }catch (RuntimeException e) {
            System.out.println(e.getMessage());
            return;
           }}
           //用户登录
        while (true) {
            System.out.println("请登录!");
            System.out.println("输入用户名:");
            String userName =sc.next();
            System.out.println("输入密码:");
            String passWord=sc.next();
            try{
                if(userService.login(userName,passWord)){
                    System.out.println("登录成功!");
                    break;
                }else {
                    System.out.println("登录失败");
                    continue;
                }
            }catch (Exception e){
                System.out.println(e.getMessage()+",请重试!");
                continue;
            }
        }
        int n;
        BookService bookService =new BookServiceImpl();
        do{
            System.out.println("---------------------------------------------------------------------------------------");
            System.out.println("Welcome To Use MyBMS!");
            System.out.println("请输入指定功能序号:");
            System.out.println("1.查询所有图书信息 2.查询指定图书信息");
            System.out.println("3.新增图书信息 4.删除图书 5.退出系统");
            n = sc.nextInt();
            if (n==5){
                System.out.println("退出成功!");
                break;
            }
            switch (n){
                case 1:
                    List<Book> books = bookService.queryBooks();
                    if (books==null){
                        System.out.println("不存在任何图书信息");
                        break;
                    }
                    books.forEach(book -> System.out.println(book));break;
                case 2:
                    System.out.println("请输入要查询图书的名字:");
                    String bookName = sc.next();
                    Book book = bookService.queryBookByBookName(bookName);
                    if (book==null){
                        System.out.println("图书不存在!");
                        break;
                    }
                    System.out.println(book);break;
                case 3:
                    System.out.println("请输入新增图书名:");
                    String newBookName = sc.next();
                    System.out.println("请输入新增图书作者:");
                    String bookAuthor =sc.next();
                    System.out.println("请输入新增图书价格:");
                    double bookPrice =sc.nextDouble();
                    System.out.println("请输入新增图书库存:");
                    int bookStock=sc.nextInt();
                    Book newBook =new Book(null,newBookName,bookAuthor,bookPrice,bookStock);
                    try{
                        System.out.println(bookService.addBook(newBook)?"新增图书成功!":"新增图书失败!");break;
                    }catch (Exception e){
                        System.out.println(e.getMessage());break;
                    }
                case 4:
                    System.out.println("请输入要删除的图书名:");
                    String removeBookName = sc.next();
                    System.out.println(bookService.removeBookByBookName(removeBookName)?"删除图书成功!":"图书不存在,删除图书失败!");
                default:
                    System.out.println("输入功能序号不存在!请重新输入!");
            }

        }while (n!=5);


    }
}

功能实现演示

一、注册和登陆功能

这里的注册和登陆功能的逻辑有些问题,只能先注册再登陆(当然在登陆操作时可以使用数据库t_user表中已经存在的数据);

流程:先注册 ->再登陆

二、查询所有书籍信息 

  • 37
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值