理论和实践的结合-----JavaSE实践项目
实践项目三: 图书馆管理系统(合作重构版)
【项目前提】
掌握java基本语法
熟悉使用流程控制
理解面向对象思想
熟练封装,继承,多态
熟悉使用接口,异常
熟悉使用集合
熟悉掌握I/o流相关操作
熟悉数据库操作
了解三层架构和常用设计模式
熟悉使用Git工具
【项目说明】
1.长期以来,人们使用传统的人工方式管理图书馆的日常业务,其操作流程比较烦琐。在借书时,读者首先将要借的书和借阅证交给工作人员,然后工作人员将每本书的信息卡片和读者的借阅证放在一个小格栏里,最后在借阅证和每本书贴的借阅条上填写借阅信息。在还书时,读者首先将要还的书交给工作人员,工作人员根据图书信息找到相应的书卡和借阅证,并填好相应的还书信息。太过于繁琐了!所以,我们需求设计一个图书管理系统来方便学生的借书和图书馆管理书籍。
2.本系统在项目3基础上进行重构操作,调整了基本流程,增加了管理员和操作员不同角色的操作图书馆的功能。
3.本系统首先需要进行登录或者注册,根据不同身份操作不同的功能。
4.管理员主要负责对操作员的基本信息管理和相关逾期金额的设定和查看。
5.操作员主要负责对读者的信息进行管理和相关图书进行管理。
6.本项目还会利于数据库进行数据的读取和存储。
项目功能流程结构图:
在练习项目三图书馆管理系统时,所有的数据操作基本就是增删改查,我一开始使用的是手动敲底层的增删改查,敲了两个模块的增删改查后发现代码量重复的操作其实非常多,每一个增删改操作就会多了个方法,但实际核心不同的也就sql语句。
部分手敲底层sql方法:
/**
* 判断用户名和密码是否存在在Operator数据库表中
* @param name
* @return true存在 false不存在
*/
public Boolean queryOperatorByNameAndPassword(String name, String password){
boolean existsFlag = false;
Connection connection=null;
Operator operator=null;
try {
QueryRunner runner = new QueryRunner();
connection = JDBCUtils.getConnection();
String sql="select name,password from operator where name=? and password=? ";
BeanHandler<Operator> handler = new BeanHandler<>(Operator.class);
operator = runner.query(connection, sql, handler, name,password);
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(connection,null,null);
}
if (operator!=null){
existsFlag=true;
}
return existsFlag;
}
/**
* 判断用户名是否存在在Operator数据库表中
* @param name
* @return true存在 false不存在
*/
public boolean queryOperatorByName(String name){
boolean existsFlag = false;
Connection connection=null;
Operator operator=null;
try {
QueryRunner runner = new QueryRunner();
connection = JDBCUtils.getConnection();
String sql="select name from operator where name=? ";
BeanHandler<Operator> handler = new BeanHandler<>(Operator.class);
operator = runner.query(connection, sql, handler, name);
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(connection,null,null);
}
if (operator!=null){
existsFlag=true;
}
return existsFlag;
}
其实仔细看针对查询的数据库语句时,核心不同的就select语句,虽然我用的是dbutils依赖包的增删改查实现类,但我任写了这么多重复代码。大大的增强了代码冗余度。这样一来,不同的表就有不同的增删改查方法,就核心sql的语句不同而已,却多出很多代码量。那么我就要将相同的地方抽出来,不同的踢出去。
下面就交出我的通用表的通用查询和通用增删改查。
/**
* 增删改通用方法
*/
public int update(String sql,Object...args) {
Connection connection=null;
PreparedStatement ps=null;
try{
//1.获取数据库连接
connection = JDBCUtils.getConnection();
//2.预编译sql语句,返回preparedStatement实例对象
ps = connection.prepareStatement(sql);
//3.填充占位符
for (int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
//4.执行
return ps.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
//5.关闭资源
JDBCUtils.closeResource(connection,null,ps);
}
return 0;
}
/**
* 通用表通用查询返回一个集合
* @param clazz 查询实体类
* @param sql 查询语句
* @param args 查询字段
* @param <T>
* @return 数据集合
*/
public <T> List<T> getForList(Class<T> clazz, String sql, Object...args){
Connection connection = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
try {
connection = JDBCUtils.getConnection();
ps = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
//执行,获取结果集
resultSet = ps.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
//通过结果集获取元数据再获取列的个数
int columnCount = metaData.getColumnCount();
ArrayList<T> list = new ArrayList<>();
while (resultSet.next()) {
//创建实体类对象
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
//通过ResultSet获取每个列的列值
Object columnValue = resultSet.getObject(i + 1);
//通过ResultSetMetaData获取每个列的列名,当数据库表中的列名和java中类中的属性名不一样时会报错
//解决方法就是获取列的别名
// String columnName = metaData.getColumnName(i+1);
String columnLabel = metaData.getColumnLabel(i + 1);
//通过反射将对象指定名columnLabel的属性赋值为指定的值columnValue
Field declaredField = clazz.getDeclaredField(columnLabel);
declaredField.setAccessible(true);
declaredField.set(t, columnValue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(connection, resultSet,ps );
}
return null;
}
/**
* 通用所有表的通用查询
* @param clazz 需要查询的实体类类名
* @param sql 查询语句
* @param args 要查询的列
* @param <T> 泛型
* @return 一个实体类对象
*/
public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
Connection connection = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
try {
connection = JDBCUtils.getConnection();
ps = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
//执行,获取结果集
resultSet = ps.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
//通过结果集获取元数据再获取列的个数
int columnCount = metaData.getColumnCount();
if (resultSet.next()) {
//创建实体类对象
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
//通过ResultSet获取每个列的列值
Object columnValue = resultSet.getObject(i + 1);
//通过ResultSetMetaData获取每个列的列名,当数据库表中的列名和java中类中的属性名不一样时会报错
//解决方法就是获取列的别名
// String columnName = metaData.getColumnName(i+1);
String columnLabel = metaData.getColumnLabel(i + 1);
//通过反射将对象指定名columnLabel的属性赋值为指定的值columnValue
Field declaredField = clazz.getDeclaredField(columnLabel);
declaredField.setAccessible(true);
declaredField.set(t, columnValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(connection, resultSet, ps);
}
return null;
}
这样一来不同的表就针对增删改就传入实体类的反射和占位符变量就好了,针对查询就传入实体类的反射和sql语句和占位符变量就好了。就让这些数据库数据操作类继承这个通用增删改查类。
以下改变后的操作数据库增删改查dao类:
/**
* 获取指定图书类别的图书集合
* @param readerType
* @return BookListByBookType
*/
public List<Reader> geReaderListByReaderType(String readerType){
String sql="select reader_number readerNumber,type_number typeNumber," +
"reader_type readerType,name,age,sex,phone,department," +
"record_date recordDate FROM reader WHERE reader_type=?";
return getForList(Reader.class, sql, readerType);
}
/**
* 通过readerNUmber获取该读者对象
* @param readerNumber
* @return reader
*/
public Reader geReaderByReaderNumber(int readerNumber){
String sql="select reader_number readerNumber,type_number typeNumber," +
"reader_type readerType,name,age,sex,phone,department," +
"record_date recordDate FROM reader WHERE reader_number=?";
return getInstance(Reader.class,sql,readerNumber);
}
/**
* 插入一个新读者对象到数据库中
* @param reader
* @return true成功 ,false失败
*/
public boolean insertReader(Reader reader){
String sql = "insert into reader (type_number,reader_type,name,age,sex,phone,department,record_date) values (?,?,?,?,?,?,?,?)";
int update = update(sql,reader.getTypeNumber(),reader.getReaderType(), reader.getName(),
reader.getAge(),reader.getSex(),reader.getPhone(),reader.getDepartment(),reader.getRecordDate());
if (update>0){
return true;
}else {
return false;
}
}
/**
* 更新一个读者对象到数据库中
* @param reader
* @return true成功 ,false失败
*/
public boolean updateReader(Reader reader) {
String sql = "update reader set type_number=?,reader_type=?,name=?,age=?," +
"sex=?,phone=?,department=?,record_date=? where reader_number=?";
int update = update(sql, reader.getTypeNumber(),reader.getReaderType(), reader.getName(),
reader.getAge(),reader.getSex(),reader.getPhone(),reader.getDepartment(),reader.getRecordDate(),reader.getReaderNumber());
if (update > 0) {
return true;
} else {
return false;
}
}
/**
* 根据readerNumber删除指定读者
*
* @param readerNumber
* @return true删除成功,false删除失败
*/
public boolean delReader(int readerNumber) {
String sql = "delete from reader where reader_number=?";
int update = update(sql, readerNumber);
if (update > 0) {
return true;
} else {
return false;
}
}
这样就简洁了太多了!只需要编写不同的sql语句再调用父类的通用增删改查方法就行了。如果想要更简洁,就使用dbutils依赖包也行。方法展现哈哈哈哈哈哈哈。请看下面
/**
* BeanHander:是ResultSetHandler接口的实现类,用于封装表中的一条记录
*/
public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
Connection connection=null;
T c=null;
try {
QueryRunner runner = new QueryRunner();
connection = JDBCUtils.getConnection();
BeanHandler<T> handler = new BeanHandler<>(clazz);
c = runner.query(connection, sql, handler,args);
return c;
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(connection,null,null);
}
return null;
}
/**
*BeanListHander:是ResultSetHander接口的实现类,用于封装表中多条记录构成的集合
* @param cls Class
* @param sql SQL
* @param params param
* @param <T> type
* @return dataList
*/
public static <T> List<T> queryForList(Class<T> cls, String sql, Object... params){
Connection connection = null;
List<T> list = null;
try {
QueryRunner runner = new QueryRunner();
connection = JDBCUtils.getConnection();
BeanListHandler<T> beanListHandler = new BeanListHandler<>(cls);
list = runner.query(connection, sql, beanListHandler, params);
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(connection, null, null);
}
return null;
}
/**
* 通用表的通用增删改
* @param sql SQL语句
* @param args 占位符数组
* @return 操作条目数
*/
public int update(String sql,Object...args){
Connection connection=null;
try{
QueryRunner queryRunner = new QueryRunner();
connection = JDBCUtils.getConnection();
int insertCount = queryRunner.update(connection, sql, args);
return insertCount;
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(connection,null,null);
}
return 0;
}
```