1.数据库中新建一个t_type表,含有id和type_name属性,id为bigint类型,type_name为varchar类型。
输入一些图书类别
2.纯后端实现
- 实体类Type,在entity包,注意和以前的实体类的区别,使用了数据绑定属性
package com.soft1841.book.entity;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;
/**
* 类别实体类
*/
public class Type {
//以JavaFX属性绑定的形式,定义和数据表字段id和type_name对应的属性,注意命名规范
private final SimpleLongProperty id = new SimpleLongProperty();
private final SimpleStringProperty typeName = new SimpleStringProperty("");
public Type() {
}
public Type(long id, String typeName) {
setId(id);
setTypeName(typeName);
}
public long getId() {
return id.get();
}
public SimpleLongProperty idProperty() {
return id;
}
public void setId(long id) {
this.id.set(id);
}
public String getTypeName() {
return typeName.get();
}
public SimpleStringProperty typeNameProperty() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName.set(typeName);
}
@Override
public String toString() {
return typeName.get();
}
}
- DAO接口TypeDAO,在dao包,先写接口,再创建impl子包
package com.soft1841.book.dao;
import cn.hutool.db.Entity;
import com.soft1841.book.entity.Type;
import java.sql.SQLException;
import java.util.List;
/**
* 图书类别DAO接口
*/
public interface TypeDAO {
/**
* 新增图书类别, 返回自增主键(Long)
* @param type
* @return
*/
Long insertType(Type type) throws SQLException;
/**
* 根据id删除类别
* @param id
* @return
*/
int deleteTypeById(long id) throws SQLException;
/**
* 查询所有类别
* @return
*/
List<Entity> selectAllTypes() throws SQLException;
/**
* 根据id查询类别信息
* @param id
* @return
*/
Entity getTypeById(int id) throws SQLException;
}
- DAO实现类,在dao下的impl子包
package com.soft1841.book.dao.impl;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.soft1841.book.dao.TypeDAO;
import com.soft1841.book.entity.Type;
import java.sql.SQLException;
import java.util.List;
public class TypeDAOImpl implements TypeDAO {
@Override
public Long insertType(Type type) throws SQLException {
//采用了另一种新增方法,可以返回插入记录的主键(Long类型)
return Db.use().insertForGeneratedKey(
Entity.create("t_type")
.set("type_name", type.getTypeName())
);
}
@Override
public int deleteTypeById(long id) throws SQLException {
return Db.use().del(
Entity.create("t_type").set("id", id)
);
}
@Override
public List<Entity> selectAllTypes() throws SQLException {
//1.采用默认的查询
//return Db.use().findAll("t_type");
//2.采用自定义查询语句查询
return Db.use().query("SELECT * FROM t_type ");
}
@Override
public Entity getTypeById(int id) throws SQLException {
//采用自定义带参查询语句,返回单个实体
return Db.use().queryOne("SELECT * FROM t_type WHERE id = ? ", id);
}
}
- 工厂类,在utils包,统一管理各个DAO接口,采用静态方法,这样无论在哪里调用,都是一个实例
package com.soft1841.book.utils;
import com.soft1841.book.dao.TypeDAO;
import com.soft1841.book.dao.impl.TypeDAOImpl;
/**
* 工厂类,用静态方法来生成各个DAO实例
*/
public class DAOFactory {
/**
* 静态方法,返回TypeDAO实现类的对象
* @return
*/
public static TypeDAO getTypeDAOInstance() {
return new TypeDAOImpl();
}
}
- 封装的组件类ComponentUtil ,用来在界面上生成“编辑”、“删除”等按钮
package com.soft1841.book.utils;
import javafx.scene.control.Button;
public class ComponentUtil {
//根据传入的文字和主题返回一个按钮
public static Button getButton(String text, String theme) {
Button button = new Button(text);
button.getStyleClass().add(theme);
return button;
}
}
- 单元测试,测试TypeDAO接口中的各个方法,注意自己根据实际情况修改
package com.soft1841.book.dao;
import cn.hutool.db.Entity;
import com.soft1841.book.entity.Type;
import com.soft1841.book.utils.DAOFactory;
import org.junit.Test;
import java.sql.SQLException;
import java.util.List;
public class TypeDAOTest {
//通过DAO工厂获得TypeDAO的实例
private TypeDAO typeDAO = DAOFactory.getTypeDAOInstance();
@Test
public void insertType() throws SQLException {
Type type = new Type();
type.setTypeName("测试类别");
System.out.println(typeDAO.insertType(type));
}
@Test
public void deleteTypeById() throws SQLException {
typeDAO.deleteTypeById(7);
}
@Test
public void selectAllTypes() throws SQLException {
List<Entity> typeList = typeDAO.selectAllTypes();
typeList.forEach(entity -> System.out.println(entity));
}
@Test
public void getTypeById() throws SQLException {
Entity entity = typeDAO.getTypeById(1);
System.out.println(entity);
}
}
3.界面
- type.fxml布局文件,是左侧导航点击“类别管理”->“图书类别”切换的内容,调用的控制器是TypeController
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.soft1841.book.controller.TypeController">
<HBox AnchorPane.topAnchor="10" AnchorPane.leftAnchor="20" spacing="20">
<Button text="添加图书类别" styleClass="green-theme" onAction="#addType"/>
</HBox>
<!--表格视图,用来显示数据库中查询到的图书类别-->
<TableView fx:id="typeTable" prefWidth="700"
AnchorPane.leftAnchor="20" AnchorPane.topAnchor="50">
<columns>
<!--ID列-->
<TableColumn text="ID">
<!--绑定实体类中的id属性-->
<cellValueFactory>
<PropertyValueFactory property="id"/>
</cellValueFactory>
</TableColumn>
<!--类别名称列-->
<TableColumn text="类别名称">
<!--绑定实体类中的typeName属性-->
<cellValueFactory>
<PropertyValueFactory property="typeName"/>
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</AnchorPane>
- 图书类别控制器TypeController.java,用来创建模型数据,和数据库查询的类别数据做绑定后在表格输出。控制器是前后端联系的桥梁
package com.soft1841.book.controller;
import cn.hutool.db.Entity;
import com.soft1841.book.dao.TypeDAO;
import com.soft1841.book.entity.Type;
import com.soft1841.book.utils.ComponentUtil;
import com.soft1841.book.utils.DAOFactory;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import java.net.URL;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
public class TypeController implements Initializable {
//获得布局文件中的表格对象
@FXML
private TableView<Type> typeTable;
//定义ObservableList数据集合
private ObservableList<Type> typeData = FXCollections.observableArrayList();
//通过工厂类获得TypeDAO的实例
private TypeDAO typeDAO = DAOFactory.getTypeDAOInstance();
//定义实体集合,用来存放数据库查询结果
private List<Entity> entityList = null;
private TableColumn<Type, Type> delCol = new TableColumn<>("操作");
@Override
public void initialize(URL location, ResourceBundle resources) {
//水平方向不显示滚动条
typeTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
//在表格最后加入删除按钮
delCol.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()));
delCol.setCellFactory(param -> new TableCell<Type, Type>() {
private final Button deleteButton = ComponentUtil.getButton("删除", "warning-theme");
@Override
protected void updateItem(Type type, boolean empty) {
super.updateItem(type, empty);
if (type == null) {
setGraphic(null);
return;
}
setGraphic(deleteButton);
//点击删除按钮,需要将这一行从表格移除,同时从底层数据库真正删除
deleteButton.setOnAction(event -> {
//删除操作之前,弹出确认对话框,点击确认按钮才删除
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("确认对话框");
alert.setHeaderText("请确认");
alert.setContentText("确定要删除这行记录吗?");
Optional<ButtonType> result = alert.showAndWait();
//点击了确认按钮,执行删除操作,同时移除一行模型数据
if (result.get() == ButtonType.OK){
typeData.remove(type);
try {
typeDAO.deleteTypeById(type.getId());
} catch (SQLException e) {
e.printStackTrace();
}
}
});
}
});
//删除列加入表格
typeTable.getColumns().add(delCol);
try {
entityList = typeDAO.selectAllTypes();
} catch (SQLException e) {
e.printStackTrace();
}
showTypeData(entityList);
}
public void addType() {
//创建一个输入对话框
TextInputDialog dialog = new TextInputDialog("新类别");
dialog.setTitle("图书类别");
dialog.setHeaderText("新增图书类别");
dialog.setContentText("请输入图书类别名称:");
Optional<String> result = dialog.showAndWait();
// result.ifPresent(name -> System.out.println("你的输入: " + name));
//确认输入了内容
if (result.isPresent()) {
//获得输入的内容
String typeName = result.get();
//创建一个Type对象,插入数据库,并返回主键
Type type = new Type();
type.setTypeName(typeName);
long id = 0;
try {
id = typeDAO.insertType(type);
} catch (SQLException e) {
e.printStackTrace();
}
type.setId(id);
//加入ObservableList,刷新模型视图,不用重新查询数据库也可以立刻看到结果
typeData.add(type);
}
}
private void showTypeData(List<Entity> entityList) {
//遍历实体集合
for (Entity entity : entityList) {
//取出属性,创建Type的对象
Type type = new Type();
type.setId(entity.getInt("id"));
type.setTypeName(entity.getStr("type_name"));
//加入ObservableList模型数据集合
typeData.add(type);
}
typeTable.setItems(typeData);
}
}
5.图书类别管理实现效果
可以查看所有类别,新增、删除,并且无需手动刷新。删除之前有提示信息。