how2j.cn


工具版本兼容问题
学习了这么多J2SE基础和中级的知识点,接下来就需要一个综合性的项目把这些的知识点都融会贯通

本项目是基于Swing和JDBC开发的图形界面桌面应用,涵盖了J2SE的绝大部分基础知识,通过这个项目能运用和锻炼几乎大部分的J2SE知识和技能。

涉及到如下内容:
基础内容:
面向对象 字符串数字 日期

中级内容:
异常 ,集合,JDBC, 反射机制,I/O,Swing, 利用TableModel更新数据, 图形界面的皮肤

高级内容:
图表chart动态生成,数据库的备份与恢复,自定义圆形进度条

软件设计思想:
单例模式,面板类与监听器类松耦合,Entity层设计,DAO层设计,Service层设计

业务常见处理手法:
CRUD操作,配置信息,配置信息初始化,报表生成,一对多关系,多对一关系

通过本项目,积累宝贵的项目经验,在面试的时候,多一项谈资多一层砝码多一些薪水



18分18秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。 chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器




HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。


最近10个提问
2022-01-13 我成功完成站长的修改要求啦!
Alex97




一个类中有静态变量、静态方法、静态代码块、成员变量、成员方法、非静态代码块、构造器,那么他们执行的顺序是什么呢?如果该类继承了父类,那么执行顺序又是什么样的呢? 正常情况下:超类的静态变量和代码块 - - - > 父类的静态变量和代码块 - - - > 子类的静态变量和代码块 - - - > 超类的非静态变量和代码块- - - > 超类的构造器 - - - > 父类的非静态变量和代码块 - - - > 父类的构造器 - - - > 子类的非静态变量和代码块 - - - > 子类的构造器 ———————————————— 基础不牢,地动山摇 public class DetailByCategoryTableModel implements TableModel { int cid; public List<Record> rs = new ArrayList<>(); String[] columnNames = new String[]{"花费¥", "分类","备注","日期"}; // 使用从Service返回的List作为TableModel的数据 public DetailByCategoryTableModel(int cid) { this.cid = cid; rs = new RecordService().list(cid); } 之前是 public List<Record> rs=new RecordService().list(cid); rs.size一直是0,弄了一个多小时.
加载中
package gui.listener;

import entity.Category;
import gui.panel.*;
import service.RecordService;
import util.GUIUtil;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

public class DetailEditListener implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
       DetailEdit p =DetailEdit.instance;
        if (0==p.cbModel.cs.size()){
            JOptionPane.showMessageDialog(p,"暂无消费分类,无法添加,请先增加消费分类");
            MainPanel.instance.workingPanel.show(CategoryPanel.instance);
            return;
        }

        if (!GUIUtil.checkZero(p.tfSpend,"花费金额"))
            return;

        int spend = Integer.parseInt(p.tfSpend.getText());
        Category c =p.getSelectedCategory();
        String comment = p.tfComment.getText();
        Date d = p.datepick.getDate();
        new RecordService().update(p.id,spend,c,comment,d);
        JOptionPane.showMessageDialog(p,"修改成功");

        p.setVisible(false);
        MainPanel.instance.workingPanel.show(DetailPanel.instance);

    }
}
___________________________________________________________________________
package gui.listener;

import entity.Category;
import entity.Record;
import gui.model.DetailByCategoryTableModel;
import gui.panel.DetailEdit;
import gui.panel.DetailPanel;
import service.CategoryService;
import service.RecordService;

import javax.swing.*;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.List;

public class DetailListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        DetailPanel p = DetailPanel.instance;
        JButton b = (JButton) e.getSource();

        if (b == p.bEdit) {
            Record r = p.getSelectedRecord();
            DetailEdit de = DetailEdit.instance;
            de.setVisible(true);
            de.setRecord(r);

        }
        if (b == p.bDelete) {
            Record r = p.getSelectedRecord();
            if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(p, "确认要删除?"))
                return;

            int id = r.id;
            new RecordService().delete(id);
        }

        if (b==p.bSelect){
            Category selectedItem=(Category)p.cbCategory.getSelectedItem();
            int cid =selectedItem.id;
            DetailByCategoryTableModel dbctm=new DetailByCategoryTableModel(cid);
            JTable t = new JTable(dbctm);
            t.setVisible(true);
            JDialog jDialog = new JDialog();
            jDialog.add(t);
            jDialog.setBounds(100,100,400,300);
            jDialog.setVisible(true);

        }

        p.updateData();
    }
}
_______________________________________________________________________
package gui.model;

import com.sun.org.apache.xpath.internal.SourceTree;
import entity.Record;
import service.CategoryService;
import service.RecordService;

import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class DetailByCategoryTableModel implements TableModel {
    int cid;
    public List<Record> rs = new ArrayList<>();
    String[] columnNames = new String[]{"花费¥", "分类","备注","日期"};
    // 使用从Service返回的List作为TableModel的数据
    public DetailByCategoryTableModel(int cid) {
        this.cid = cid;
        rs = new RecordService().list(cid);
    }



    @Override
    public int getRowCount() {
        return rs.size();
    }


    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public String getColumnName(int columnIndex) {
        return columnNames[columnIndex];
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        if (columnIndex==0){return Integer.class;}
        if (columnIndex==1){return String.class;}
        if (columnIndex==2){return String.class;}
        if (columnIndex==3){return Date.class;}
        return null;
    }


    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
    }

    // 先通过cs.get(rowIndex)获取行对应的Category对象
    // 然后根据columnIndex返回对应的属性
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Record h = rs.get(rowIndex);
        if (0 == columnIndex)
            return h.spend;
        if (1 == columnIndex){
            CategoryService cs  = new CategoryService();
            return cs.get(h.cid).name;}
        if (2 == columnIndex)
            return h.comment;
        if (3 == columnIndex)
            return h.date;
        return null;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {

    }

    @Override
    public void addTableModelListener(TableModelListener l) {

    }

    @Override
    public void removeTableModelListener(TableModelListener l) {

    }
}
________________________________________________________________
package gui.model;


import entity.Record;

import service.CategoryService;
import service.RecordService;

import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import java.util.Date;
import java.util.List;

public class DetailTableModel implements TableModel {

    String[] columnNames = new String[]{"花费¥", "分类","备注","日期"};
    // 使用从Service返回的List作为TableModel的数据
    public List<Record> rs = new RecordService().list();


    @Override
    public int getRowCount() {
        return rs.size();
    }

    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public String getColumnName(int columnIndex) {
        return columnNames[columnIndex];
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        if (columnIndex==0){return Integer.class;}
        if (columnIndex==1){return String.class;}
        if (columnIndex==2){return String.class;}
        if (columnIndex==3){return Date.class;}
        return null;
    }


    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
    }

    // 先通过cs.get(rowIndex)获取行对应的Category对象
    // 然后根据columnIndex返回对应的属性
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Record h = rs.get(rowIndex);
        if (0 == columnIndex)
            return h.spend;
        if (1 == columnIndex){
            CategoryService cs  = new CategoryService();
            return cs.get(h.cid).name;}
        if (2 == columnIndex)
            return h.comment;
        if (3 == columnIndex)
            return h.date;
        return null;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {

    }

    @Override
    public void addTableModelListener(TableModelListener l) {

    }

    @Override
    public void removeTableModelListener(TableModelListener l) {

    }

}
__________________________________________________________________
package gui.panel;

import entity.Category;
import entity.Record;
import gui.listener.DetailEditListener;

import gui.model.CategoryComboBoxModel;

import jdk.management.resource.internal.inst.SocketOutputStreamRMHooks;
import org.jdesktop.swingx.JXDatePicker;

import util.ColorUtil;
import util.GUIUtil;

import javax.swing.*;
import java.awt.*;
import java.util.Date;

public class DetailEdit extends JDialog{
    static {
        GUIUtil.useLNF();
    }

    public static DetailEdit instance = new DetailEdit();

   public int id ;
    JLabel lSpend = new JLabel("花费(¥)");
    JLabel lCategory = new JLabel("分类");
    JLabel lComment = new JLabel("备注");
    JLabel lDate = new JLabel("日期");

    public JTextField tfSpend = new JTextField("0");
    public CategoryComboBoxModel cbModel = new CategoryComboBoxModel();
    public JComboBox<Category> cbCategory = new JComboBox<>(cbModel);
    public JTextField tfComment = new JTextField();
    public JXDatePicker datepick = new JXDatePicker(new Date());
    JButton bSubmit = new JButton("确认修改");

    public DetailEdit() {
        GUIUtil.setColor(ColorUtil.grayColor, lSpend, lCategory, lComment, lDate);
        GUIUtil.setColor(ColorUtil.blueColor, bSubmit);
        JPanel pInput = new JPanel();
        JPanel pSubmit = new JPanel();
        int gap = 40;
        pInput.setLayout(new GridLayout(4, 2, gap, gap));
        pInput.add(lSpend);
        pInput.add(tfSpend);
        pInput.add(lCategory);
        pInput.add(cbCategory);
        pInput.add(lComment);
        pInput.add(tfComment);
        pInput.add(lDate);
        pInput.add(datepick);
        pSubmit.add(bSubmit);

        this.setLayout(new BorderLayout());
        this.add(pInput, BorderLayout.NORTH);
        this.add(pSubmit, BorderLayout.CENTER);

        this.setBounds(100,100,300,300);
        addListener();
    }

    public static void main(String[] args) {
        DetailEdit de = new DetailEdit();
        de.setVisible(true);
    }

    public void setRecord(Record record) {
        tfSpend.setText(""+record.spend);
        cbCategory.setSelectedIndex(0);
        tfComment.setText(record.comment);
        datepick.setDate(record.date);
        id = record.id;
    }

    public Category getSelectedCategory(){
        return (Category)cbCategory.getSelectedItem();
    }
    public void addListener() {
        DetailEditListener listener = new DetailEditListener();
        bSubmit.addActionListener(listener);
    }
}

_________________________________________________________
package gui.panel;

import entity.Category;
import entity.Record;
import gui.listener.DetailListener;
import gui.model.CategoryComboBoxModel;
import gui.model.DetailTableModel;
import service.RecordService;
import util.ColorUtil;
import util.GUIUtil;

import javax.swing.*;
import java.awt.*;

public class DetailPanel extends WorkingPanel {
    static {
        GUIUtil.useLNF();
    }

    public static DetailPanel instance = new DetailPanel();

    public JButton bEdit = new JButton("编辑");
    public JButton bDelete = new JButton("删除");
    public JButton bSelect = new JButton("筛选");
    public CategoryComboBoxModel cbModel = new CategoryComboBoxModel();
    public JComboBox<Category> cbCategory = new JComboBox<>(cbModel);

    String columNames[] = new String[]{"花费¥", "分类", "备注", "日期"};

    public DetailTableModel dtm = new DetailTableModel();
    public JTable t = new JTable(dtm);

    public DetailPanel() {
        GUIUtil.setColor(ColorUtil.blueColor, bEdit, bDelete,bSelect);
        JScrollPane sp = new JScrollPane(t);
        JPanel pSubmit = new JPanel();
        pSubmit.add(bEdit);
        pSubmit.add(bDelete);
        pSubmit.add(bSelect);
        pSubmit.add(cbCategory);

        this.setLayout(new BorderLayout());
        this.add(sp, BorderLayout.CENTER);
        this.add(pSubmit, BorderLayout.SOUTH);
        addListener();
    }

    public static void main(String[] args) {
        GUIUtil.showPanel(DetailPanel.instance);
    }

    public Record getSelectedRecord() {
        int index = t.getSelectedRow();
        return dtm.rs.get(index);
    }

    @Override
    public void updateData() {
        dtm.rs = new RecordService().list();
        t.updateUI();
        t.getSelectionModel().setSelectionInterval(0,0);

        if (0==dtm.rs.size()) {
            bEdit.setEnabled(false);
            bDelete.setEnabled(false);
        }else {
            bEdit.setEnabled(true);
            bDelete.setEnabled(true);
        }

    }

    @Override
    public void addListener() {
        DetailListener listener = new DetailListener();
        bEdit.addActionListener(listener);
        bDelete.addActionListener(listener);
        bSelect.addActionListener(listener);
    }
}

							





回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2022-01-09 CategoryTableModel 由 implement TableModel改成现在代码上的"extends AbstractTableModle"
Alex97




一,使用implement TableModel 在"原型_界面类"章节里,categoryTableModle使用的是 implement TableModel,其中有个重写方法,需要重写为 public Class<?> getColumnClass(int columnIndex) { if (columnIndex==0){return String.class;} if (columnIndex==1){return int.class;} return null; }. 不重写的话会报空指针异常,并且分类面板崩溃. 二,改为extends AbstractTableModle 否则,应该提示将"implement TableModle"改成现在代码上的"extends AbstractTableModle",并删除getColumnClass方法
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        if (columnIndex==0){return String.class;}
        if (columnIndex==1){return int.class;}
        return null;
    }
D:\JDK\bin\java "-javaagent:D:\IDEA\IntelliJ IDEA 2017.2\lib\idea_rt.jar=3672:D:\IDEA\IntelliJ IDEA 2017.2\bin" -Dfile.encoding=UTF-8 -classpath D:\JDK\jre\lib\charsets.jar;D:\JDK\jre\lib\deploy.jar;D:\JDK\jre\lib\ext\access-bridge.jar;D:\JDK\jre\lib\ext\cldrdata.jar;D:\JDK\jre\lib\ext\dnsns.jar;D:\JDK\jre\lib\ext\jaccess.jar;D:\JDK\jre\lib\ext\jfxrt.jar;D:\JDK\jre\lib\ext\localedata.jar;D:\JDK\jre\lib\ext\nashorn.jar;D:\JDK\jre\lib\ext\sunec.jar;D:\JDK\jre\lib\ext\sunjce_provider.jar;D:\JDK\jre\lib\ext\sunmscapi.jar;D:\JDK\jre\lib\ext\sunpkcs11.jar;D:\JDK\jre\lib\ext\zipfs.jar;D:\JDK\jre\lib\javaws.jar;D:\JDK\jre\lib\jce.jar;D:\JDK\jre\lib\jfr.jar;D:\JDK\jre\lib\jfxswt.jar;D:\JDK\jre\lib\jsse.jar;D:\JDK\jre\lib\management-agent.jar;D:\JDK\jre\lib\plugin.jar;D:\JDK\jre\lib\resources.jar;D:\JDK\jre\lib\rt.jar;D:\project\hutubill\out\production\hutubill;D:\project\hutubill\lib\liquidlnf.jar;D:\project\hutubill\lib\chart.jar;D:\project\hutubill\lib\swingx-core-1.6.2.jar;D:\project\hutubill\lib\mysql-connector-java-5.0.8-bin.jar startup.BootStrap

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at javax.swing.JTable.prepareRenderer(JTable.java:5723)
	at com.birosoft.liquid.LiquidTableUI.paintCell(LiquidTableUI.java:298)
	at com.birosoft.liquid.LiquidTableUI.paintCells(LiquidTableUI.java:190)
	at com.birosoft.liquid.LiquidTableUI.paint(LiquidTableUI.java:101)
	at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
	at javax.swing.JComponent.paintComponent(JComponent.java:780)
	at javax.swing.JComponent.paint(JComponent.java:1056)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JViewport.paint(JViewport.java:728)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
	at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
	at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
	at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
	at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
	at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
	at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
	at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
	at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
	at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
	at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at javax.swing.JTable.prepareRenderer(JTable.java:5723)
	at com.birosoft.liquid.LiquidTableUI.paintCell(LiquidTableUI.java:298)
	at com.birosoft.liquid.LiquidTableUI.paintCells(LiquidTableUI.java:190)
	at com.birosoft.liquid.LiquidTableUI.paint(LiquidTableUI.java:101)
	at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
	at javax.swing.JComponent.paintComponent(JComponent.java:780)
	at javax.swing.JComponent.paint(JComponent.java:1056)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JViewport.paint(JViewport.java:728)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JComponent.paintChildren(JComponent.java:889)
	at javax.swing.JComponent.paint(JComponent.java:1065)
	at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
	at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
	at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
	at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
	at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
	at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
	at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
	at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
	at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
	at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
	at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)





回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2022-01-04 PreparedStatement和Statement
2021-12-22 没有代码
2021-12-13 已按站长要求改进
2021-12-13 请教为啥这里的DAO不是接口,在spring天猫版里的DAO都是接口?
2021-12-10 作业
2021-11-22 我第一次忘了输出为sql文件,然后后面重新创建一直显示这个问题
2021-11-16 整个项目从哪里开始运行呢
2021-11-14 1




提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
关于 实践项目-一本糊涂账-项目简介 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 496725845
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: https://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图