我有一个带有两个表的MySQl数据库; user和user_role。
表用户包含字段: (PK)int user_id string user_name 字符串密码 string firstName 字符串LastName (FK)int role_id
表user_role包含字段: (PK)int role_id string role_type
我有一个tableview,我想根据组合框表格单元格从用户表中编辑role_id。我需要组合框表格单元格包含role_type作为字符串名称,但返回role_id的字符串。
我有两个模型UserModel和RoleModel。 RoleModel包含从数据库中检索的role_id和role_type。 UserModel从用户表中检索所有字段,并在TableView中显示该字段。我想要实现的是一个表格单元格组合框,其中包含user_role表中的所有记录,当进行选择时,它将为用户更改存储在后端数据库中的值。如果需要实现所需的结果,我不确定如何将两个类UserModel和RoleModel合并在一起。或者有替代解决方案吗?
public class RoleModel {
private final StringProperty roleId;
private final StringProperty roleName;
public RoleModel(String roleId, String roleName){
this.roleId = new SimpleStringProperty(roleId);
this.roleName = new SimpleStringProperty(roleName);
}
public String getId() {return roleId.get(); }
public String getRoleName() { return roleName.get(); }
public StringProperty roleIdProperty(){ return roleId; }
public StringProperty roleNameProperty(){ return roleName; }
public void setRoleId(String roleId){this.roleId.set(roleId);}
public void setRoleName(String roleName){this.roleName.set(roleName);}
}
public class UserModel {
private final StringProperty userId;
private final StringProperty userName;
private final StringProperty password;
private final StringProperty roleName;
private final StringProperty firstName;
private final StringProperty lastName;
public UserModel(String userId, String userName, String password, String roleName, String firstName, String lastName){
this.userId = new SimpleStringProperty(userId);
this.userName = new SimpleStringProperty(userName);
this.password = new SimpleStringProperty(password);
this.roleName = new SimpleStringProperty(roleName);
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
}
public String getUserId(){
return userId.get();
}
public String getUserName(){
return userName.get();
}
public String getPassword(){
return password.get();
}
public String getRoleName(){
return roleName.get();
}
public String getFirstName(){
return firstName.get();
}
public String getLastName(){
return lastName.get();
}
public void setUserId(String id){
this.userId.set(id);
}
public void setUserName(String userName){
this.userName.set(userName);
}
public void setPassword(String password){
this.password.set(password);
}
public void setRoleName(String role){
this.roleName.set(role);
}
public void setFirstName(String firstName){
this.firstName.set(firstName);
}
public void setLastName(String lastName){
this.lastName.set(lastName);
}
public StringProperty userIdProperty(){
return userId;
}
public StringProperty userNameProperty(){
return userName;
}
public StringProperty passwordProperty(){
return password;
}
public StringProperty roleNameProperty(){
return roleName;
}
public StringProperty firstNameProperty(){
return firstName;
}
public StringProperty lastNameProperty(){
return lastName;
}
}
public class UserController implements Initializable{ //Initializable allows tagged FXML to be accessed
//Create form variables
@FXML
private TextField userName;
@FXML
private TextField password;
@FXML
private ComboBox<RoleModel> role;
@FXML
private TextField firstName;
@FXML
private TextField lastName;
@FXML
private Button btnAddUser;
//Create table variables using UserModel
@FXML
private TableView<UserModel> userTable;
@FXML
private TableColumn<UserModel, String> idColumn;
@FXML
private TableColumn<UserModel, String> userNameColumn;
@FXML
private TableColumn<UserModel, String> passwordColumn;
@FXML
private TableColumn<UserModel, String> roleColumn;
@FXML
private TableColumn<UserModel, String> firstNameColumn;
@FXML
private TableColumn<UserModel, String> lastNameColumn;
private DBConnection DBconnection; //Create a DBConnection object to access the database
private ObservableList<UserModel> userData; //Create array to store data from the user table
private ObservableList<RoleModel> roleType; //Create array to store data from the role table
@Override
public void initialize(URL url, ResourceBundle resourceBundle){
this.DBconnection = new DBConnection();
try {
setupCellValueFactories();
loadUserData(); //Call method to load the user table when the window opens
loadRoleOptions();
populateRolesCombobox(); //Call method to load role type into the role combobox
setupUserNameColumn();
setupPasswordColumn();
setupRoleColumn();
setupFirstNameColumn();
setupLastNameColumn();
setTableEditable();
} catch (SQLException error) {
System.err.print(error);
}
}
private void setupCellValueFactories(){
this.idColumn.setCellValueFactory(new PropertyValueFactory<>("userId"));
this.userNameColumn.setCellValueFactory(new PropertyValueFactory<>("userName"));
this.passwordColumn.setCellValueFactory(new PropertyValueFactory<>("password"));
this.roleColumn.setCellValueFactory(new PropertyValueFactory<>("roleName"));
this.firstNameColumn.setCellValueFactory(new PropertyValueFactory<>("firstName"));
this.lastNameColumn.setCellValueFactory(new PropertyValueFactory<>("lastName"));
}
@FXML
private void addUser(ActionEvent event) {
String SQL = "INSERT INTO user (user_name, password, first_name, last_name, role_id) VALUES (?,?,?,?,?)";
try {
Connection connection = DBConnection.getConnection();
PreparedStatement statement = connection.prepareStatement(SQL);
statement.setString(1, this.userName.getText());
statement.setString(2, this.password.getText());
statement.setString(3, this.firstName.getText());
statement.setString(4, this.lastName.getText());
statement.setString(5, this.role.getSelectionModel().getSelectedItem().getId());
statement.execute();
connection.close();
this.userName.setText("");
this.password.setText("");
this.firstName.setText("");
this.lastName.setText("");
loadUserData();
} catch (SQLException error) {
System.err.print(error);
}
}
@FXML
private void deleteUser(){
PreparedStatement statement;
String SQL = "DELETE user \n" +
"FROM mpd_production.user \n" +
"WHERE user_id = ?";
try{
Connection connection = DBConnection.getConnection(); //Create a connection to the database
statement = connection.prepareStatement(SQL);
statement.setString(1, userTable.getSelectionModel().getSelectedItem().getUserId());
statement.executeUpdate();
connection.close();
loadUserData();
} catch (SQLException error){
System.out.println(error);
}
}
private void updateUser(String newValue, String columnName){
String SQL = "";
switch(columnName) {
case "userName":
SQL = "UPDATE user SET user_name = ? WHERE user_id = ?";
break;
case "password":
SQL = "UPDATE user SET password = ? WHERE user_id = ?";
break;
case "role":
SQL = "UPDATE user SET role_id = ? WHERE user_id = ?";
break;
case "firstName":
SQL = "UPDATE user SET first_name = ? WHERE user_id = ?";
break;
case "lastName":
SQL = "UPDATE user SET last_name = ? WHERE user_id = ?";
break;
}
PreparedStatement statement;
try{
Connection connection = DBConnection.getConnection(); //Create a connection to the database
statement = connection.prepareStatement(SQL);
statement.setString(1, newValue);
statement.setString(2, userTable.getSelectionModel().getSelectedItem().getUserId());
statement.executeUpdate();
connection.close();
loadUserData();
} catch (SQLException error){
System.out.println(error);
}
}
private void setupUserNameColumn(){
//sets the cell factory to use Editcell which will handle key press
//and firing commit events
this.userNameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
this.userNameColumn.setOnEditCommit(new EventHandler<CellEditEvent<UserModel, String>>(){
@Override
public void handle(CellEditEvent Event){
updateUser(Event.getNewValue().toString(), "userName");
}
});
}
private void setupPasswordColumn(){
//sets the cell factory to use Editcell which will handle key press
//and firing commit events
this.passwordColumn.setCellFactory(TextFieldTableCell.forTableColumn());
this.passwordColumn.setOnEditCommit(new EventHandler<CellEditEvent<UserModel, String>>(){
@Override
public void handle(CellEditEvent Event){
updateUser(Event.getNewValue().toString(), "password");
}
});
}
private void setupRoleColumn(){
//sets the cell factory to use Editcell which will handle key press
//and firing commit events
this.roleColumn.setCellFactory(ComboBoxTableCell.forTableColumn());
this.roleColumn.setOnEditCommit(new EventHandler<CellEditEvent<UserModel, String>>(){
@Override
public void handle(CellEditEvent Event){
updateUser(Event.getNewValue().toString(), "role");
System.out.println(Event.getNewValue());
}
});
}
private void setupFirstNameColumn(){
this.firstNameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
this.firstNameColumn.setOnEditCommit(new EventHandler<CellEditEvent<UserModel, String>>(){
@Override
public void handle(CellEditEvent Event){
updateUser(Event.getNewValue().toString(), "firstName");
}
});
}
private void setupLastNameColumn(){
this.lastNameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
this.lastNameColumn.setOnEditCommit(new EventHandler<CellEditEvent<UserModel, String>>(){
@Override
public void handle(CellEditEvent Event){
updateUser(Event.getNewValue().toString(), "lastName");
}
});
}
//This method populates the role combobox
public void populateRolesCombobox(){
this.role.setItems(roleType); //Set the items of the combobox to the roleData
this.role.setCellFactory(roleTypeFactory);
this.role.setButtonCell(roleTypeFactory.call(null));
}
private void setTableEditable(){
userTable.setEditable(true); //Allows the individual cells to be selected
userTable.getSelectionModel().cellSelectionEnabledProperty().set(true); //When characters or numbers are pressed it will start the edit in the editable fields
userTable.setOnKeyPressed(event -> {
if(event.getCode().isLetterKey() || event.getCode().isDigitKey()){
editFocusedCell();
} else if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.TAB){
userTable.getSelectionModel().selectNext();
event.consume();
} else if (event.getCode() == KeyCode.LEFT){
selectPrevious();
event.consume();
}
});
}
private void editFocusedCell(){
final TablePosition<UserModel, ?> focusedCell = userTable.focusModelProperty().get().focusedCellProperty().get();
userTable.edit(focusedCell.getRow(), focusedCell.getTableColumn());
}
private void selectPrevious(){
if(userTable.getSelectionModel().isCellSelectionEnabled()){
//in the cell selection mode, we have to wrap around, going from
//right-to-left, and then wrapping to the end of the previous line
TablePosition<UserModel, ?> pos = userTable.getFocusModel().getFocusedCell();
if(pos.getColumn() - 1 >= 0){
//go to previous row
userTable.getSelectionModel().select(pos.getRow(), getTableColumn(pos.getTableColumn(), -1));
} else if(pos.getRow() < userTable.getItems().size()) {
//wrap to end of the previous row
userTable.getSelectionModel().select(pos.getRow() - 1, userTable.getVisibleLeafColumn(userTable.getVisibleLeafColumns().size() - 1));
} else {
int focusIndex = userTable.getFocusModel().getFocusedIndex();
if(focusIndex == - 1){
userTable.getSelectionModel().select(userTable.getItems().size() - 1);
} else if(focusIndex > 0) {
userTable.getSelectionModel().select(focusIndex - 1);
}
}
}
}
private TableColumn<UserModel, ?> getTableColumn(final TableColumn<UserModel, ?> column, int offset){
int columnIndex = userTable.getVisibleLeafIndex(column);
int newColumnIndex = columnIndex + offset;
return userTable.getVisibleLeafColumn(newColumnIndex);
}
private void loadUserData()throws SQLException{
String SQL = "SELECT user.user_id, user.user_name, user.password, user_role.role_name, user.first_name, user.last_name\n" + //Create SQL query to pull data from user table
"FROM user_role\n" +
"INNER JOIN user ON user_role.role_id = user.role_id ";
try {
Connection connection = DBConnection.getConnection(); //Create a connection to the Database
this.userData = FXCollections.observableArrayList(); //Generate array
ResultSet resultSet = connection.createStatement().executeQuery(SQL); //Execute the SQL string and store that data in the results set object
while (resultSet.next()){ //Loop through the data until the method next() can no longer be called
this.userData.add(new UserModel(resultSet.getString(1),resultSet.getString(2),resultSet.getString(3), resultSet.getString(4), resultSet.getString(5), resultSet.getString(6)));
}
connection.close();
} catch (SQLException error) {
System.err.println("Error " + error);
}
this.userTable.setItems(this.userData);
}
private void loadRoleOptions(){
String SQL = "SELECT role_id, role_name \n" + //Generate SQL query to pull related data
"FROM mpd_production.user_role;";
try {
Connection connection = DBConnection.getConnection(); //Create a connection to the database
this.roleType = FXCollections.observableArrayList();
ResultSet resultSet = connection.createStatement().executeQuery(SQL); //Execute the SQL string and store that data in the results set object
while (resultSet.next()){ //Loop through the data until the method next() can no longer be called
this.roleType.add(new RoleModel(resultSet.getString("role_id"), resultSet.getString("role_name"))); //Store role_id and role_name into the roleData array
}
connection.close(); //Finally, close the connection
} catch (SQLException error) {
System.out.println(error);
}
}
Callback<ListView<RoleModel>, ListCell<RoleModel>> roleTypeFactory = listView -> new ListCell<RoleModel>(){
@Override
protected void updateItem(RoleModel item, boolean empty){
super.updateItem(item, empty);
setText(empty ? "" : item.getRoleName());
}
};
}
答案 0 :(得分:0)
看起来UserModel#role
应该是ObservableValue<RoleModel>
而roleColumn
应该是TableColumn<UserModel, RoleModel>
类型。
public ObjectProperty<StringConverter<T>> converterProperty()
将用户输入的输入(当ComboBox可编辑时)转换为对象 类型为T,这样可以通过value属性检索输入。
StringConverter#fromString
仅在将文本输入可编辑ComboBox
时使用,以选择与输入文本匹配的值。它不能用于在此上下文中将角色的字符串值自动转换为RoleModel
对象。这就是您获得ClassCastException
的原因,因为它试图将字符串值直接转换为RoleModel
。
此外,ComboBoxTableCell.forTableColumn
使用TableCells
和<S, T>
类型StringConverter
返回一个单元格工厂,以创建ObservableList
类型的<T>
。
因此,使用返回的单元工厂的TableColumn
的第二个参数化类型必须与字符串转换器的类型匹配。
上面的代码试图填充TableColumn<UserModel, String>
TableCells
类型<UserModel, RoleModel>
,然后用字符串数据填充TableCells
。