swing实现MVC模式实现增删改查+排序系统3.0
swing实现MVC模式实现增删改查+排序系统3.0
MVC模式应用
❀顾客类(面向对象)、
❀顾客窗体类(样式、视图层)、
❀数据库类(提供测试数据)、
❀表格模式类(数据层、核心逻辑类,修改表格模式、处理业务)
ps:这次整个项目代码的注解的分析更加详细易懂噢!!!
1.顾客类:属性:姓名、年龄、卡号、电话等,get、set方法
2.顾客窗体类:
样式:卡号标签、电话标签、两个文本框、一个搜索按钮、 一张表格:
3.自己暂时定义一个数据库类:存放List的数据,static静态块初始化,List集合的元素。用来作为提供数据测试使用的。
4.由于DefaultTableModel默认表格模式,存放的数据是Vector或者二维数组的数据,而我们的数据是List类型,所以,我们自定了一个DefaultTableModel 的兄弟类(继承父类呀、实现接口呀与DefaultTableModel一样)–表格模式类:
5、表格模式类:兼容我们的数据类型List,所以定义了List<顾客类>的集合。//顾客类的List集合,通过构造方法,我们要求传入的是一个List的集合。
华丽的分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(至此四个类已经全部出现)
1.看一下:表格模式类:兼容我们的数据类型List,所以定义了List<顾客类>的集合。//顾客类的List集合,通过构造方法,我们要求传入的是一个List的集合。( 顾客数据层,自己实现表格模式,因为DefauleTableModel 处理的数据类型时Vector,而我们想要实现处理List型数据)
2. 表格模式类实现的三个方法+后边我们想要的一些方法:先重点看一下getValueAt(int rowIndex, int columIndex)方法获取值的实现:
2-1.先获取到行数据(某个对象的数据):Customer cust = custList.get(rowIndex); (custLIst就是替换DefauleTableMode,我们自己的表格模式类,我们用来存放数据的List集合)
2-2.在获取到列数据时出现问题:
①发现:想要取出的对象属性没有先后之分,可能会导致我们的属性位置放错了,没给我们设置一种模式让我们取
②发现:(某个对象的某个属性–与当前的参数列下标columnIndex要没有联系)
解决:
★考虑如果传入当前的列下标的话,我们可以获取到对应表头名称;
★通过列名挂钩到对象的属性–借助桥梁(Map集合<列名,属性名>)(通过反射实现);
★通过map的列名key获取map的属性名(value);
★获取到顾客对象的属性;(反射应用啦): field = Customer.class.getDeclaredField(fileName); (fields是“反射变量”, fileName 是map的属性名,通过map挂钩到对象属性啦)
★通过属性反射,获取到该属性是哪一个对象的属性:Object fieldValue = field.get(cust); (cust 是2-1,获取的某个对象的数据)
(2-1)
(2-2的问题)
(2-2解决:(Map集合<列名,属性名>))
★ getValueAt(int rowIndex, int columIndex)方法代码:
//设置表格的单元格的值 @Override public Object getValueAt(int rowIndex, int columnIndex) { if(custList == null) return null; //先获取到行数据(某个对象的数据) Customer cust = custList.get(rowIndex); //获取到列数据(某个对象的某个属性--与当前的列下标要有联系) // Object custProperty = cust.get //当前的列下标传入的话,可以获取到对应表头名称 // String columnName = tableHeaderName.get(columnIndex); String columnName = tableHeaderName[columnIndex]; //通过列名挂钩到对象的属性--借助桥梁(Map集合<列名,属性名>)(通过反射实现) //通过列名key获取属性名(value) String fileName = map.get(columnName); Field field = null; try { //获取到顾客对象的属性 field = Customer.class.getDeclaredField(fileName); //设置访问权限为true field.setAccessible(true); //通过属性反射,获取到该属性是哪一个对象的属性 Object fieldValue = field.get(cust); //设置访问权限为false field.setAccessible(false); return fieldValue; } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } return null; }
3. 其实在第2点实现前,我们做完了大概表格模式后,先测试一下,使用我们自定的表格模式,拿我们自定义的数据库类数据做测试。不过样式:
(样子没那么完美,列名是A,B,C,D)
解决:列名是A,B,C,D不完美:重写getColumnName(int column)方法。改为返回表头的名称:
华丽的分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(至此,表格的模式实现了我们想要的啦,接下来我们有业务需求啦)
业务分析请看:放到最后啦
整个项目的全部代码:
❀顾客类(面向对象)
package com.xuetang9.kenny.MVCDemo; /** * 顾客类 * @author Huangyujun * */ public class Customer implements Comparable<Customer>{ private String cardId; //卡号 private String telPhone; //电话 private String name; //姓名 private int age; //年龄 public Customer() { }; public Customer(String cardId, String name, String telPhone, int age) { super(); this.cardId = cardId; this.telPhone = telPhone; this.name = name; this.age = age; } @Override public int compareTo(Customer o) { return this.cardId.compareTo(o.cardId); } public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } public String getTelPhone() { return telPhone; } public void setTelPhone(String telPhone) { this.telPhone = telPhone; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
❀顾客窗体类(样式、视图层)
package com.xuetang9.kenny.MVCDemo; /** * 顾客视图层 * @author Huangyujun * */ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; public class CustomerView extends JFrame{ //内容面板 JPanel searchPane = new JPanel(); //标签 JLabel lblCard = new JLabel("卡号:"); JLabel lblTel = new JLabel("电话:"); //文本框 JTextField txtCard = new JTextField(); JTextField txtTel = new JTextField(); //搜索按钮 JButton searchButton = new JButton("搜索"); //排序按钮 JButton sortButton = new JButton("排序"); //表格 JTable table = new JTable(); //增加按钮 JButton addButton = new JButton("添加"); //右键弹出菜单 JPopupMenu popMenu = new JPopupMenu(); //删除菜单项 JMenuItem delMenuItem = new JMenuItem("删除顾客"); //修改菜单项 JMenuItem modifyMenuItem = new JMenuItem("修改顾客"); //实例化CustomerModel,List集合是来自数据库的 CustomerModel customerModel = new CustomerModel(MyDataBase.custList); public CustomerView() { //设置标题 setTitle("顾客管理系统"); //设置退出模式 setDefaultCloseOperation(EXIT_ON_CLOSE); //设置大小 setSize(800, 600); //居中 setLocationRelativeTo(null); //封装其余部分的初始话工作 initComponents(); //事件 initEvent(); } private void initComponents() { //设置文本框大小 txtCard.setPreferredSize(new Dimension(160, 30)); txtTel.setPreferredSize(new Dimension(160, 30)); //面板添加标签、文本框、搜索按钮、表格 searchPane.add(lblCard); searchPane.add(txtCard); searchPane.add(lblTel); searchPane.add(txtTel); searchPane.add(searchButton); searchPane.add(sortButton); // searchPane.add(table); //菜单添加删除菜单项 popMenu.add(delMenuItem); //菜单添加修改菜单项 popMenu.add(modifyMenuItem); //表格添加右键菜单 table.add(popMenu); //设置表格模型 table.setModel(customerModel); //内容面板添加搜索面板(布局面板) getContentPane().add(searchPane, BorderLayout.NORTH); getContentPane().add(addButton, BorderLayout.SOUTH); //添加表格到内容面板 getContentPane().add(new JScrollPane(table), BorderLayout.CENTER); } private void initEvent() { //为添加按钮添加事件 addButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //业务的实现都是在数据层(逻辑层)--调用逻辑层的方法即可 Customer cust = new Customer("007", "汉堡可乐", "11122233344", 20); CustomerView.this.customerModel.addCustomer(cust); } }); //为表格添加右键菜单的事件 table.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if(e.getButton() == MouseEvent.BUTTON3) { //右键鼠标 popMenu.show(table, e.getX(), e.getY()); } } }); //(删除菜单项)添加事件 delMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //先获取单元格所处在表格的行 int delRow = table.getSelectedRow(); //通过行获取到对象的卡号,调用数据层的 getValueAt(int rowIndex, int columnIndex)方法 String cardId = (String) CustomerView.this.customerModel.getValueAt(delRow, 0); //调用数据层的删除对象方法 CustomerView.this.customerModel.delCustomer(cardId); } }); //(修改菜单项)添加事件 modifyMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Customer cust = new Customer("000", "炸鸡炸鸡", "11122266677", 00); //先获取单元格所处在表格的行 int modifyRow = table.getSelectedRow(); //调用数据层的修改对象方法 CustomerView.this.customerModel.modifyCustomer(cust, modifyRow); } }); //搜索按钮添加上事件 searchButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //恢复数据 CustomerView.this.customerModel. recover(); //获取文本框的文本内容 String strContent = txtCard.getText(); if("".equals(strContent)) return; //把文本内容传递给数据层处理 //调用数据层的查找对象方法 CustomerView.this.customerModel.searchByTxtCard(strContent); } }); sortButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //默认升序 CustomerView.this.customerModel.sortByCardId(); } }); } public static void main(String[] args) { new CustomerView().setVisible(true); } }
❀数据库类(提供测试数据)
package com.xuetang9.kenny.MVCDemo; import java.util.ArrayList; import java.util.List; /** * 数据库类 * @author Huangyujun * */ public class MyDataBase { public static List<Customer> custList = null; static { custList = new ArrayList<Customer>(); Customer cust1 = new Customer("001", "小盼", "13421127777", 18); Customer cust2 = new Customer("002", "小金", "13531121111", 18); Customer cust3 = new Customer("003", "小花", "13421126666", 18); custList.add(cust1); custList.add(cust2); custList.add(cust3); } }
❀表格模式类(数据层、核心逻辑类,修改表格模式、处理业务)
package com.xuetang9.kenny.MVCDemo; /** * 顾客数据层,自己实现表格模式,因为DefauleTableModel 处理的数据类型时Vector,而我们想要实现处理List型数据 * @author Huangyujun * */ import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.table.AbstractTableModel; public class CustomerModel extends AbstractTableModel implements Serializable{ List<Customer> custList = null; // List<String> tableHeaderName = null; String[] tableHeaderName = null; Map<String, String> map = null; //构造方法,要传入List集合作为参数 public CustomerModel(List<Customer> custList) { this.custList = custList; //表头名称 // tableHeaderName = new ArrayList<String>(); // tableHeaderName.addAll(Arrays.asList("卡号", "姓名", "电话", "年龄")); tableHeaderName = new String[] {"卡号", "姓名", "电话", "年龄"}; map = new HashMap(); map.put("卡号", "cardId"); map.put("姓名", "name"); map.put("电话", "telPhone"); map.put("年龄", "age"); } //实现业务:增删改查 /** * 1.增加对象 * @param cust */ public void addCustomer(Customer cust) { //内部List添加顾客对象 custList.add(cust); //更新一下数据 fireTableDataChanged(); } /** * 2.删除对象--通过卡号删除对象 * @param cardId */ public void delCustomer(String cardId) { Customer delCust = searchByCardId(cardId); custList.remove(delCust); //更新一下数据 fireTableDataChanged(); } /** * 查找--根据视图层传递的文本内容查找 * @param strContent */ public void searchByTxtCard(String strContent) { //定义一个存放查找到的结果的List,用来替换掉原来的List List<Customer> resultList = new ArrayList<Customer>(); for(Customer customer : custList) { if(strContent.equals(customer.getCardId())) { resultList.add(customer); } } custList = resultList; //更新一下数据 fireTableDataChanged(); } /** * 根据传入的行号和传入的顾客对象,修改对应的行号的对象为新对象 * @param cust * @param modifyRow */ public void modifyCustomer(Customer cust, int modifyRow) { //更改List中的对象 custList.set(modifyRow, cust); //更新一下数据 fireTableDataChanged(); } /** * 根据卡号排序,默认升序 */ public void sortByCardId() { //使用Collections工具类排序 // Collections.sort(custList, new Comparator<Customer>() { // @Override // public int compare(Customer o1, Customer o2) { // return o1.getCardId().compareTo(o2.getCardId()); // } // }); Collections.sort(custList); //更新一下数据 fireTableDataChanged(); } //复位数据--恢复数据 public void recover() { custList = MyDataBase.custList; //更新一下数据 fireTableDataChanged(); } /** * 根据卡号查找对象,找到并返回对象 * @param cardId * @return */ public Customer searchByCardId(String cardId) { Customer cust = null; for(Customer customer : custList) { if(cardId.equals(customer.getCardId())) { cust = customer; break; } } return cust; } @Override //返回表格的行数,即List的对象的数量 public int getRowCount() { if(custList == null) return 0; return custList.size(); } //重写表头名称 @Override public String getColumnName(int column) { return tableHeaderName[column]; } @Override public int getColumnCount() { // return tableHeaderName.size(); return tableHeaderName.length; } //设置表格的单元格的值 @Override public Object getValueAt(int rowIndex, int columnIndex) { if(custList == null) return null; //先获取到行数据(某个对象的数据) Customer cust = custList.get(rowIndex); //获取到列数据(某个对象的某个属性--与当前的列下标要有联系) // Object custProperty = cust.get //当前的列下标传入的话,可以获取到对应表头名称 // String columnName = tableHeaderName.get(columnIndex); String columnName = tableHeaderName[columnIndex]; //通过列名挂钩到对象的属性--借助桥梁(Map集合<列名,属性名>)(通过反射实现) //通过列名key获取属性名(value) String fileName = map.get(columnName); Field field = null; try { //获取到顾客对象的属性 field = Customer.class.getDeclaredField(fileName); //设置访问权限为true field.setAccessible(true); //通过属性反射,获取到该属性是哪一个对象的属性 Object fieldValue = field.get(cust); //设置访问权限为false field.setAccessible(false); return fieldValue; } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } return null; } }
业务分析请看
1. 添加对象:
1-1. 逻辑层:List集合添加完对象,表视图还不知道数据更新了,需要通过fireTableDateChanged();通知一下。
1-2.视图层搞一个按钮:
按钮添加上事件: 按钮.addActionListener(),事件里在表格模式添加上对象即可,不用操作表格,操作的是表格模式。
总结一下:增删改查操作,都不用在界面层操作,都是操作数据层(逻辑层),然后添加上对应操作的控件后,加事件,事件里只需要操作表格模型(逻辑层)
2. 删除对象:
2-1.视图层:通过右键菜单删除选中对象
实例化右键菜单,和菜单项,然后右键菜单里添加菜单项。
2-2.表格控件添加右键鼠标事件:表格.addMouseListener(鼠标监听适配器)方法,实现鼠标点击方法,效果:在表格上右键鼠标,弹出删除对象提醒。
2-3.要删除的菜单项添加事件:在视图层获取到要删除的对象的卡号(卡号是主键噢),再把视图层要删除的卡号传递给数据层(逻辑层,表格模式),在数据层找到对应要删除的对象,然后remove( );最后fireTableDataChanged();通知一下数据更新啦!
bug:新添加的对象,不能删除,why?(ps:项目代码我改了这个bug啦)
3. 查找:
3-1.视图层:查找按钮添加事件监听:通过卡号文本框的文本,判断要查找的内容。
3-2逻辑层:
bug:就是查找一次后,第二次查找不灵光了,数据变成了第一次查找后的结果。
解决:(复位,恢复数据层数据)
4. 改功能
5.排序功能: