问题
The system I'm developing is a till system and the JTable
acts as the orderList
. I've tried Vector
and I've tried to use DefaultTableModel
but I'm not sure how to make the button pull the data and for it to add to the table. I know that this is quite hard to follow but could anyone maybe show me how I should do it for one JButton
and then the rest should be similar, I can do those myself?
I need productID
, productName
and Price
to be pulled from DB and added to table.
I will then total the price and take payment for the order.
Order
//Order class for setting up and managing an order
package classes;
import java.sql.*;
import java.util.ArrayList;
import java.util.Vector;
public class Order
{
// Instance Variables
private int productID;
private String productName;
private String productDescription;
private String type;
private String supplierName;
private double quantity;
private double price;
// Connection To DB
// JDBC Driver name and database URL
final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
final String DB_URL = "jdbc:mysql://localhost/team_project?useSSL=false";
final String USER_NAME = "root";
final String PASSWORD = "password";
// sql variables
ResultSet resultSet = null;
private String itemName;
private double itemPrice;
// Constructors
public Order()
{
}
public Order(int productID, String itemName, double itemPrice, double quantity)
{
this.itemName = itemName;
this.itemPrice = itemPrice;
this.quantity = quantity;
}
// Get the details of stock items and add them to the order
public Vector getOrderItems()
{
ResultSet rs = null;
Statement statement = null;
try{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
Statement stmt = conn.createStatement();
String sqlString= "select ProductID, ProductName, Price from product";
stmt.executeUpdate(sqlString);
Vector vector = new Vector();
Vector<String> orderItem = new Vector<String>();
int i=0;
while(rs.next())
{
Vector<String> items = new Vector<String>();
rs.getInt("ProductID");
rs.getString("ProductName");
rs.getDouble("Price");
}
return vector;
}catch(Exception e)
{
e.printStackTrace();
}
return null;
}
// Getter Methods
public int getProductID()
{
return productID;
}
public String getProductName()
{
return productName;
}
public String getProductDesc()
{
return productDescription;
}
public String getType()
{
return type;
}
public String getSupplierName()
{
return supplierName;
}
public double getQuantity()
{
return quantity;
}
public double getPrice()
{
return price;
}
}
Stock
// Stock class
//Team Project
//Stock class for setting up and managing stock
package classes;
import java.sql.*;
import java.util.*;
public class Stock
{
// Instance Variables
private int productID;
private String productName;
private String productDescription;
private String type;
private String supplierName;
private double quantity;
private double price;
// JDBC Driver name and database URL
final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
final String DB_URL = "jdbc:mysql://localhost/team_project?useSSL=false";
final String USER_NAME = "root";
final String PASSWORD = "password";
// sql variables
Statement statement = null;
ResultSet resultSet = null;
public Stock()
{
productID=0;
productName=null;
productDescription = null;
type = null;
supplierName=null;
quantity = 0;
price=0;
}
// Initialisation Constructor that initializes everything in DB
public Stock(int productID, String productName, String productDescription, String type, String supplierName,
double quantity, double price)
{
this.productID = productID;
this.productName = productName;
this.productDescription = productDescription;
this.type = type;
this.supplierName = supplierName;
this.quantity = quantity;
this.price = price;
}
// Add a new product into the product table
public void addProduct(int prodID, int amt)
{
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
Statement stmt = conn.createStatement();
String sqlString="insert into product " + "(ProductID, ProductName, ProductDescrp, type, SupplierName, Quantity, Price)"
+ " values(30, 'Marmalade', 'Homestead', 'Extras', 'Bakersworld', 20, 0.20)";
stmt.executeUpdate(sqlString);
conn.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
// Delete a product from the product table
public void delete(int prodNumIn)
{
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
Statement stmt = conn.createStatement();
String sqlString= "delete from team_Project.product where ProductID=" + prodNumIn;
stmt.executeUpdate(sqlString);
}
catch(Exception e)
{
e.printStackTrace();
}
}
// Subtracts quantity in stock in the DB When a sale is made on an item
public int deductStock(int prodID)
{
int status =0;
String sql = ("UPDATE product " + "SET Quantity = " + (getDBQuantity(prodID)-1) + " WHERE ProductID = " + prodID);
status = databaseUpdate(sql);
return status;
}
// Add quantity to particular product in the DB if required
public int addToQuantity(int prodID, int amt)
{
int status =0;
String sql = ("UPDATE product " + "SET Quantity = " + (getDBQuantity(prodID)+ amt) + " WHERE ProductID = " + prodID);
status = databaseUpdate(sql);
return status;
}
// return quantity of a product in DB
public int getDBQuantity(int prodID)
{
int quantity=0;
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = (Statement) conn.createStatement();
resultSet = statement.executeQuery("select Quantity from team_project.product WHERE ProductID = " + prodID);
while (resultSet.next())
{
quantity = (resultSet.getInt("Quantity"));
}
conn.close();
}catch(Exception e)
{
e.printStackTrace();
}
return quantity;
}
// get price of a particular product
public int getItemPrice(int prodID)
{
int price = 0;
try{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = (Statement) conn.createStatement();
resultSet = statement.executeQuery("select Price from team_project.product WHERE ProductID = " + prodID);
while (resultSet.next())
{
price = (resultSet.getInt("Price"));
}
conn.close();
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("€"+price);
return price;
}
// Method that returns all products in product table
public ArrayList<Stock> getProducts()
{
ArrayList<Stock> allStock = new ArrayList<Stock>();
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = (Statement) conn.createStatement();
resultSet = statement.executeQuery("select * from team_project.product");
while (resultSet.next())
{
Stock stock = new Stock(resultSet.getInt("ProductID"), resultSet.getString("ProductName"),
resultSet.getString("ProductDescrp"),resultSet.getString("Type"),resultSet.getString("SupplierName"),
resultSet.getInt("Quantity"), resultSet.getDouble("Price"));
allStock.add(stock);
}
conn.close();
}catch(Exception e)
{
e.printStackTrace();
}
return allStock;
}
// update method to call
// database update method
private int databaseUpdate(String sqlUpdate)
{
int status = 0;
try{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = conn.createStatement();
status = statement.executeUpdate(sqlUpdate);
conn.close();
}
catch (Exception e) {
e.printStackTrace();
}
return status;
}
// toString method for stock items
public String toString()
{
return productName + "";
}
// Getter Methods
public int getProductID()
{
return productID;
}
public String getProductName()
{
return productName;
}
public String getProductDesc()
{
return productDescription;
}
public String getType()
{
return type;
}
public String getSupplierName()
{
return supplierName;
}
public double getQuantity()
{
return quantity;
}
public double getPrice()
{
return price;
}
}
// Small Americano Listener
americanoSmall.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try {
String query = "select ProductName, Price from product where ProductID = 24";
java.sql.PreparedStatement pst = connection.prepareStatement(query);
ResultSet rs = pst.executeQuery();
table.setModel(DbUtils.resultSetToTableModel(rs));
} catch (Exception e1)
{
e1.printStackTrace();
}
}
});
回答1:
You code is a little skewed, you have a Stock
object, but that object seems to be also managing the database, as a more long term solution, I would recommend separating those concerns, but for now we'll leave that for the time been.
The first thing I would do is define the expectations of the model, what do you expect it to do, how do you expect it to work
public interface MutableStockModel {
public void add(Stock item) throws ModelException;
public void remove(Stock item) throws ModelException;
}
So this is a simple interface which defines a couple of actions which any implementing class is expected to provide. But why you ask? That's a good question I'll answer shortly.
You could extend the MutableStockModel
from a TableModel
, but that locks you into a particular implementation channel which may not meet your long term needs, besides, what does any one using it care, they just want to be able to add and remove products
An example implementation...
public class DefaultStockTableModel extends AbstractTableModel implements MutableStockModel {
private List<Stock> items;
public DefaultStockTableModel() {
items = new ArrayList<>(25);
}
public DefaultStockTableModel(List<Stock> items) {
this.items = items;
}
@Override
public int getRowCount() {
return items.size();
}
@Override
public int getColumnCount() {
return 7;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 1:
case 2:
case 3:
case 4: return String.class;
case 0:
case 5:
case 7: return int.class;
}
return Object.class;
}
@Override
public String getColumnName(int column) {
switch (column) {
case 0: return "ID";
case 1: return "Name";
case 2: return "Description";
case 3: return "Type";
case 4: return "Supplier Name";
case 5: return "Quanity";
case 6: return "Price";
}
return null;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Stock item = items.get(rowIndex);
switch (columnIndex) {
case 0: return item.getProductID();
case 1: return item.getProductName();
case 2: return item.getProductDesc();
case 3: return item.getType();
case 4: return item.getSupplierName();
case 5: return item.getQuantity();
case 6: return item.getPrice();
}
return null;
}
@Override
public void add(Stock item) throws ModelException {
// Add the item to the database if required
items.add(item);
int row = items.indexOf(item);
fireTableRowsInserted(row, row);
}
@Override
public void remove(Stock item) throws ModelException {
if (items.contains(item)) {
// Delete theitem from the database if required
int row = items.indexOf(item);
items.remove(row);
fireTableRowsDeleted(row, row);
}
}
}
So this is basic example, none of your code cares how it's actually managed, only that it meets the contractual requirements.
To add or remove a product, simply call the specific methods.
Now, you can expand this concept to make it easier to use, for example...
public interface MutableStockTableModel extends MutableStockModel, TableModel {
public void removeAt(int row) throws ModelException;
}
This is a specific, targeted implementation, which allows you to remove a row at a specific row. This extends TableModel
, because a TableModel
has a concept of "rows", which the MutableStockModel
doesn't. Of course, you'd have to update any implementations implement
this particular interface
;)
Okay, but "why"?
The short answer is, depending on the database, the ResultSet
can actually be mutated directly, that is, you can add/insert, remove and update rows directly via the ResultSet
, see Retrieving and Modifying Values from Result Sets for more details.
This means you could create an implementation of a TableModel
which implements the MutableStockTableModel
or MutableStockModel
interfaces but which took a reference to the original ResultSet
as it's internal structure.
Sounds, simple, but when you realise you can change any instance of the TableModel
for any implementation which meet the implementation requirements without affecting any of your code, it opens up a swagger of possibilities.
So, for example, instead of using TableModel
or DefaultTableModel
in your code, you might use
private MutableStockTableModel tableModel;
//...
tableModel = new ResultSetMutableStockTableModel(resultSet);
table.setModel(tableModel);
//...
tableModel.add(stockItem);
But you could simply change the tableModel
for a different instance...
tableModel = new DefaultStockTableModel(listOfItems);
and nothing else needs to change!
So, this is basic example of "coding to interface, not implementation" and I could decouple the code further, but I don't want to overwhelm you ;)
Going back to my first comment, OO promotes the Single Responsibility Principle, meaning that any object should have a single responsibility (or job).
This might suggest that, for example, you should separate the functionality of your Stock
class.
My, I'd start with, surprise, a interface
...
public interface Stock {
public int getProductID();
public String getProductName();
public String getProductDesc();
public String getType();
public String getSupplierName();
public double getQuantity();
public double getPrice();
}
And then you'd have some kind of implementation...
public class DefaultStock implements Stock {
// Instance Variables
private int productID;
private String productName;
private String productDescription;
private String type;
private String supplierName;
private double quantity;
private double price;
public DefaultStock() {
productID = 0;
productName = null;
productDescription = null;
type = null;
supplierName = null;
quantity = 0;
price = 0;
}
// Initialisation Constructor that initializes everything in DB
public DefaultStock(int productID, String productName, String productDescription, String type, String supplierName,
double quantity, double price) {
this.productID = productID;
this.productName = productName;
this.productDescription = productDescription;
this.type = type;
this.supplierName = supplierName;
this.quantity = quantity;
this.price = price;
}
// toString method for stock items
@Override
public String toString() {
return productName + "";
}
// Getter Methods
@Override
public int getProductID() {
return productID;
}
@Override
public String getProductName() {
return productName;
}
@Override
public String getProductDesc() {
return productDescription;
}
@Override
public String getType() {
return type;
}
@Override
public String getSupplierName() {
return supplierName;
}
@Override
public double getQuantity() {
return quantity;
}
@Override
public double getPrice() {
return price;
}
}
And then you might have some kind of manager/controller/factory...
(And yes, I'd be tempted to describe this through some kind of interface, but this is already a long post)
public class StockManager {
// JDBC Driver name and database URL
final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
final String DB_URL = "jdbc:mysql://localhost/team_project?useSSL=false";
final String USER_NAME = "root";
final String PASSWORD = "password";
// sql variables
Statement statement = null;
ResultSet resultSet = null;
// Add a new product into the product table
public void addProduct(int prodID, int amt) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
Statement stmt = conn.createStatement();
String sqlString = "insert into product " + "(ProductID, ProductName, ProductDescrp, type, SupplierName, Quantity, Price)"
+ " values(30, 'Marmalade', 'Homestead', 'Extras', 'Bakersworld', 20, 0.20)";
stmt.executeUpdate(sqlString);
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// Delete a product from the product table
public void delete(int prodNumIn) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
Statement stmt = conn.createStatement();
String sqlString = "delete from team_Project.product where ProductID=" + prodNumIn;
stmt.executeUpdate(sqlString);
} catch (Exception e) {
e.printStackTrace();
}
}
// Subtracts quantity in stock in the DB When a sale is made on an item
public int deductStock(int prodID) {
int status = 0;
String sql = ("UPDATE product " + "SET Quantity = " + (getDBQuantity(prodID) - 1) + " WHERE ProductID = " + prodID);
status = databaseUpdate(sql);
return status;
}
// Add quantity to particular product in the DB if required
public int addToQuantity(int prodID, int amt) {
int status = 0;
String sql = ("UPDATE product " + "SET Quantity = " + (getDBQuantity(prodID) + amt) + " WHERE ProductID = " + prodID);
status = databaseUpdate(sql);
return status;
}
// return quantity of a product in DB
public int getDBQuantity(int prodID) {
int quantity = 0;
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = (Statement) conn.createStatement();
resultSet = statement.executeQuery("select Quantity from team_project.product WHERE ProductID = " + prodID);
while (resultSet.next()) {
quantity = (resultSet.getInt("Quantity"));
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return quantity;
}
// get price of a particular product
public int getItemPrice(int prodID) {
int price = 0;
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = (Statement) conn.createStatement();
resultSet = statement.executeQuery("select Price from team_project.product WHERE ProductID = " + prodID);
while (resultSet.next()) {
price = (resultSet.getInt("Price"));
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("€" + price);
return price;
}
// Method that returns all products in product table
public ArrayList<Stock> getProducts() {
ArrayList<Stock> allStock = new ArrayList<Stock>();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = (Statement) conn.createStatement();
resultSet = statement.executeQuery("select * from team_project.product");
while (resultSet.next()) {
Stock stock = new DefaultStock(resultSet.getInt("ProductID"), resultSet.getString("ProductName"),
resultSet.getString("ProductDescrp"), resultSet.getString("Type"), resultSet.getString("SupplierName"),
resultSet.getInt("Quantity"), resultSet.getDouble("Price"));
allStock.add(stock);
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return allStock;
}
// update method to call
// database update method
private int databaseUpdate(String sqlUpdate) {
int status = 0;
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
statement = conn.createStatement();
status = statement.executeUpdate(sqlUpdate);
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return status;
}
}
I'd also encourage you to have a look at Using Prepared Statements to improve the code overall
回答2:
Part one
First : When you want to use SELECT you have to use stmt.executeQuery(sqlString);
or stmt.execute(sqlString);
instead of executeUpdate
it used when you want to make a an insert update or delete:
stmt.executeQuery(sqlString);
Second : I think you are missing something in your URL you are missing the port number :
"jdbc:mysql://localhost/team_project?useSSL=false";
//---------------------^--------------------------
It should be like this, the default port of MySQL is 3306
:
"jdbc:mysql://localhost:3306/team_project?useSSL=false";
Note using statement is not safe, it can cause a syntax error or SQL Injection, instead i suggest to use PreparedStatement, it is more secure and more helpful
Part two
To populate your JTable i usually use this way :
//call this method to fill your Object in your JTable when you click to your button
private void fillData(List<MY_OBJECT> list) {//method which take a list of objects
DefaultTableModel model = (DefaultTableModel) jTableName.getModel();
// empty your JTable
model.setRowCount(0);
//Fill your JTbale
for (MY_OBJECT obj : list) {
model.addRow(new Object[]{
obj.getAttribute1(),
obj.getAttribute2,
obj.getAttribute3
});
}
}
回答3:
here is a Minimal, Complete, and Verifiable example (MCVE) how to populate the table:
public class TableAddRowButton {
public static class Order {
static int idCounter = 0;
private int productID = ++idCounter;
private String productName = "Product" + productID;
private double quantity = new Random().nextInt(1000);
private double price = new Random().nextInt(1000);
}
public static void main(String[] args) {
Vector<Order> orders = new Vector<>();
DefaultTableModel tableModel = createTableModel(orders);
JButton button = createAddRowButton(orders, tableModel);
JPanel panel = new JPanel(new BorderLayout());
panel.add(button, BorderLayout.NORTH);
panel.add(new JScrollPane(new JTable(tableModel)));
JOptionPane.showMessageDialog(null, panel);
}
private static JButton createAddRowButton(Vector<Order> orders, DefaultTableModel tableModel) {
JButton button = new JButton(new AbstractAction("add row") {
@Override
public void actionPerformed(ActionEvent arg0) {
orders.add(new Order());
tableModel.fireTableRowsInserted(orders.size() - 2, orders.size() - 1);
}
});
return button;
}
private static DefaultTableModel createTableModel(Vector<Order> orders) {
DefaultTableModel tableModel = new DefaultTableModel(
new Vector<>(Arrays.asList("ID", "Name", "quantity", "price")), orders.size()) {
@Override
public int getRowCount() {
return orders.size();
}
@Override
public Object getValueAt(int row, int column) {
switch (column) {
case 0:
return orders.get(row).productID;
case 1:
return orders.get(row).productName;
case 2:
return orders.get(row).quantity;
case 3:
return orders.get(row).price;
default:
return "";
}
}
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
return tableModel;
}
}
来源:https://stackoverflow.com/questions/43076871/jtable-wont-populate-when-clicking-jbutton