JAVA簡易人員管理視窗程式(未完成)

這是職訓初期製作的Swing桌面程式,只用了MVC架構中Model跟View的概念,Controller還沒拆出來。

解析度問題,Stuff看起來缺字
解析度問題,Stuff看起來缺字

另外刪除跟查詢的功能尚未完成。


他的初版-單純的新增人員視窗程式 製作過程

前情提要

這是上Java課的第二個課堂作業(第一個是用迴圈改變陣列印出來的格式)
要做出一個輸入的視窗,可以將輸入內容存入MySQL資料庫的表格中
要輸入的內容為姓名、年齡、信箱、電話、地址

以下使用的IDE為Eclipse


施作順序盤點與架構

有些說明比較籠統,可能需要搭配相關HackMD的課堂筆記進行閱讀,我會補充在文末

1.MySQL的部分

開一個資料庫叫做guiproject,新增一張表格(Table)叫user好了
user下方再開以下幾個欄位:(MySQL沒有大小寫之分)

  • 關於下方幾個欄位標題的命名格式解釋
    • e是指employee(員工)的意思,預設這是個員工資料的登錄視窗;e後方的英文就是我要新增的欄位
  • eid
    • 注意:設定為不得為null(NN),且自動新增(AI)
  • ename
    • 注意:設定為不得為null(NN)
  • eage
  • eemail
  • ephone
  • eadress
2.程式所需檔案樹狀目錄部分
  • NewGuiProject:一個Java Project
    • lib:放置mysql-connector-java-8.0.16.jar這個連接程式與資料庫工具的地方,在src下以一般folder開啟即可
    • tw.personal.agatha.view:放置Jframe視窗程式檔案的package,針對package,後方的列點省略解說
      • CountView.java:GUI視窗程式
    • tw.personal.agatha.dbutils
      • CountDB.java:設定程式與資料庫連接的檔案
    • tw.personal.agatha.entity
      • Employee.java:員工資料屬性設置區

施作細節

  • mysql-connector-java-8.0.16.jar
    • 只有複製貼進IDE中新增的lib目錄是不夠的,還得進行建構(按右鍵選Build Path中的第一個選項)
  • Employee.java
public class Employee {
    //第一步:設置五種資料的屬性
    private int eid;
    private String eName;
    private String eAge;
    private String eEmail;
    private String ePhone;
    private String eAdress;
 
    //第二步:set & get
    public int getEid() {
        return eid;
    }
    public void setEid(int eid) {
        this.eid = eid;
    }
    public String geteName() {
        return eName;
    }
    public void seteName(String eName) {
        this.eName = eName;
    }
    public String geteAge() {
        return eAge;
    }
    public void seteAge(String eAge) {
        this.eAge = eAge;
    }
    public String geteEmail() {
        return eEmail;
    }
    public void seteEmail(String eEmail) {
        this.eEmail = eEmail;
    }
    public String getePhone() {
        return ePhone;
    }
    public void setePhone(String ePhone) {
        this.ePhone = ePhone;
    }
    public String geteAdress() {
        return eAdress;
    }
    public void seteAdress(String eAdress) {
        this.eAdress = eAdress;
    }
 
    //第三步:toString
    @Override
    public String toString() {
        return "Employee [eid=" + eid + ", eName=" + eName + ", eAge=" + eAge + ", eEmail=" + eEmail + ", ePhone="
                + ePhone + ", eAdress=" + eAdress + "]";
    }
 
}


延伸閱讀:為甚麼要toString

  • CountDB.java
public class CountDB {
//第一步:設置常數,常數的命名規則為「全都大寫」
    private static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; // 到JDBC的目錄下方查找Driver並複製過來(記得去掉class)
    // 避免時區錯誤還有禁用SSL連線,加上?及後面的語句
    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/guiproject?serverTimezone=UTC&useSSL=false";
    private static final String JDBC_NAME = "root";
    private static final String JDBC_PASSWORD = "你的密碼"; // 這邊是輸入你的資料庫密碼,輸入錯誤會連線失敗
    private static Connection conn = null;
 
//第二步之一:做一個靜態代碼塊建構子
    static {
 
        try {
            Class.forName(JDBC_DRIVER);
            System.out.println("連接成功"); // 測試用的,完成可以去掉
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
//第二步之二:做一個靜態方法
    public static Connection getConnection() {
        try {
            conn = DriverManager.getConnection(JDBC_URL, JDBC_NAME, JDBC_PASSWORD);
            System.out.println("連接成功"); // 測試用的,完成可以去掉
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return conn;
    }
 
//第三步:關閉的寫法
    // PreparedStatement、Statement這些出現提示選有java.sql那個
    // *.close();出現提示全選第2個
 
    // 以下方法得是靜態的才能被同package下方的其他檔案使用
    public static void close(Connection comm) { // 傳送Driver跟驗證帳密
        if (comm != null) {
            try {
                comm.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
 
    public static void close(PreparedStatement ps) { // 傳送SQL語法(但能防止SQL注入攻擊)
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
 
    public static void close(Statement st) { // 傳送SQL語法
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
 
    public static void close(ResultSet rs) { // 接受語法後搜尋的資料與存取
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
  • CountView.java
    • 在Design工具中對視窗的外框上方點一下新增這個jar程式的標題吧(還可以加個icon)
      • 如果要加入icon,記得在src新增一個一般folder放置圖片
      • 設置透明度容易出現the frame is decorated java的錯誤提示無法預覽運行
    • 在Design工具中畫出五個項目的文字方塊(作為提示)、輸入框跟送出按紐
      • 記得對空無一物的內部點一下,修改Layout為(absolute),拖曳上去的物件才不會被固定版面給限制住
      • 記得給每條輸入框設置自訂類別
      • 送出按鈕點兩下進行以下撰寫

這是尚未開始寫將內容傳送到資料庫語法的時候的樣子:
step1to3.PNG
這是整個寫完的樣子:

public class CountView extends JFrame {
 
    private JPanel contentPane;
    private JTextField input_eName;
    private JTextField input_eAge;
    private JTextField input_eEmail;
    private JTextField input_ePhone;
    private JTextField input_eAdress;
 
    /**
     * Launch the application.
     * 
     * @return
     */
 
    public static void main(String[] args) {
 
        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { // 我在main方法加入這個代碼,可以改變JFrame的外觀
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    CountView frame = new CountView();
                    frame.setVisible(true);
 
                    frame.setLocationRelativeTo(null); // 這是視窗預設居中的功能,看個人需求,不是一個必要過程
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
 
    /**
     * Create the frame.
     */
 
    public CountView() {
        setResizable(false);
        setFont(new Font("微軟正黑體", Font.PLAIN, 12));
        setBackground(Color.WHITE);
        setIconImage(Toolkit.getDefaultToolkit().getImage(CountView.class.getResource("/img/p.png")));
        setTitle("新增人員");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 318, 232);
        contentPane = new JPanel();
        contentPane.setBackground(new Color(26, 53, 97));
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);
 
        JLabel lblNewLabel = new JLabel("姓名");
        lblNewLabel.setForeground(new Color(184, 196, 214)); // 這邊可以直接改色彩,工具預設的色彩太少了,可以用Google搜尋的Color Pikcer工具選顏色,再把RBG值填入此處
        lblNewLabel.setFont(new Font("微軟正黑體", Font.BOLD, 12));
        lblNewLabel.setBounds(22, 12, 109, 29);
        contentPane.add(lblNewLabel);
 
        JLabel lblNewLabel_1 = new JLabel("年齡");
        lblNewLabel_1.setForeground(new Color(184, 196, 214));
        lblNewLabel_1.setFont(new Font("微軟正黑體", Font.BOLD, 12));
        lblNewLabel_1.setBounds(22, 48, 79, 29);
        contentPane.add(lblNewLabel_1);
 
        JLabel lblNewLabel_1_1 = new JLabel("信箱");
        lblNewLabel_1_1.setForeground(new Color(184, 196, 214));
        lblNewLabel_1_1.setFont(new Font("微軟正黑體", Font.BOLD, 12));
        lblNewLabel_1_1.setBounds(22, 82, 79, 29);
        contentPane.add(lblNewLabel_1_1);
 
        JLabel lblNewLabel_1_1_1 = new JLabel("電話");
        lblNewLabel_1_1_1.setForeground(new Color(184, 196, 214));
        lblNewLabel_1_1_1.setFont(new Font("微軟正黑體", Font.BOLD, 12));
        lblNewLabel_1_1_1.setBounds(22, 117, 79, 29);
        contentPane.add(lblNewLabel_1_1_1);
 
        JLabel lblNewLabel_1_1_1_1 = new JLabel("地址");
        lblNewLabel_1_1_1_1.setForeground(new Color(184, 196, 214));
        lblNewLabel_1_1_1_1.setFont(new Font("微軟正黑體", Font.BOLD, 12));
        lblNewLabel_1_1_1_1.setBounds(22, 155, 79, 29);
        contentPane.add(lblNewLabel_1_1_1_1);
 
        input_eName = new JTextField();
        input_eName.setForeground(new Color(63, 81, 112));
        input_eName.setText("必填");
        input_eName.setFont(new Font("微軟正黑體", Font.BOLD, 10));
        input_eName.setBackground(new Color(232, 241, 255));
        input_eName.setBounds(57, 15, 109, 22);
        contentPane.add(input_eName);
        input_eName.setColumns(10);
 
        input_eAge = new JTextField();
        input_eAge.setForeground(new Color(63, 81, 112));
        input_eAge.setFont(new Font("微軟正黑體", Font.BOLD, 10));
        input_eAge.setColumns(10);
        input_eAge.setBackground(new Color(232, 241, 255));
        input_eAge.setBounds(57, 51, 109, 22);
        contentPane.add(input_eAge);
 
        input_eEmail = new JTextField();
        input_eEmail.setForeground(new Color(63, 81, 112));
        input_eEmail.setFont(new Font("微軟正黑體", Font.BOLD, 10));
        input_eEmail.setColumns(10);
        input_eEmail.setBackground(new Color(232, 241, 255));
        input_eEmail.setBounds(57, 85, 109, 22);
        contentPane.add(input_eEmail);
 
        input_ePhone = new JTextField();
        input_ePhone.setForeground(new Color(63, 81, 112));
        input_ePhone.setFont(new Font("微軟正黑體", Font.BOLD, 10));
        input_ePhone.setColumns(10);
        input_ePhone.setBackground(new Color(232, 241, 255));
        input_ePhone.setBounds(57, 120, 109, 22);
        contentPane.add(input_ePhone);
 
        input_eAdress = new JTextField();
        input_eAdress.setForeground(new Color(63, 81, 112));
        input_eAdress.setFont(new Font("微軟正黑體", Font.BOLD, 10));
        input_eAdress.setColumns(10);
        input_eAdress.setBackground(new Color(232, 241, 255));
        input_eAdress.setBounds(57, 158, 109, 22);
        contentPane.add(input_eAdress);
 
        JLabel lblNewLabel_2 = new JLabel("");
        lblNewLabel_2.setIcon(new ImageIcon(CountView.class.getResource("/img/3060034.png")));
        lblNewLabel_2.setBounds(188, 29, 90, 122);
        contentPane.add(lblNewLabel_2);
 
        JButton btnNewButton = new JButton("送出");
        btnNewButton.setIcon(new ImageIcon(CountView.class.getResource("/img/shine.png")));
        btnNewButton.setBackground(new Color(11, 32, 64));
        btnNewButton.setFont(new Font("微軟正黑體", Font.BOLD, 12));
        btnNewButton.setForeground(new Color(162, 215, 224));
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) { // 主要步驟應該是從雙擊按鈕撰寫按紐細節開始,上面的程式碼主要是用Design功能完成後自動生成的(除了一些我為了美化所做的更動)
                // 第一步:實體化,然後以輸入在框中的值set給Employee中出現之對應部分
                Connection conn = null;
                PreparedStatement ps = null;// 初始化這兩個值
                Employee emp = new Employee();
                emp.seteName(input_eName.getText());
                emp.seteAge(input_eAge.getText());
                emp.seteEmail(input_eEmail.getText());
                emp.setePhone(input_ePhone.getText());
                emp.seteAdress(input_eAdress.getText());
                conn = CountDB.getConnection();// 呼叫寫在CountDB中的getConnection方法
                String sql = "insert into user(eName,eAge,eEmail,ePhone,eAdress)values(?,?,?,?,?)";// 要傳輸的SQL指令
                // 最後一步:連接資料庫並修飾上方程式碼
 
                try {
                    ps = conn.prepareStatement(sql); // 這個打完編譯器會提示要不要做個try/catch,點下去變成下列形式了
                    ps.setString(1, emp.geteName());// 數字表示填入順序
                    ps.setString(2, emp.geteAge());
                    ps.setString(3, emp.geteEmail());
                    ps.setString(4, emp.getePhone());
                    ps.setString(5, emp.geteAdress());
                    // 第二步被移動到這裡了:做一個彈出視窗提示新增成功
                    int y = ps.executeUpdate();// 可寫可不寫
                    JOptionPane.showMessageDialog(null, "新增" + y + "筆資料成功");
                } catch (SQLException e1) {
                    e1.printStackTrace();
                } finally {// 不管如何必定會執行
                    CountDB.close(ps);
                    CountDB.close(conn);// 程式用完必須關閉資料庫
                }
 
                // 第三步移到最下方:把輸入的文字清空,才方便使用者新增下一筆
                input_eName.setText("");
                input_eAge.setText("");
                input_eEmail.setText("");
                input_ePhone.setText("");
                input_eAdress.setText("");
            }
        });
        btnNewButton.setBounds(184, 149, 94, 29);
        contentPane.add(btnNewButton);
 
    }

成品

finally.PNG
finally2-1.PNG


過程中其他異常的事情

  • 如果有跟我一樣加"連線成功"檢查是否連線成功,印出了3次,應該都是因為為static所以都被載入
  • 如果有更動資料庫的表格內容,要按Apply再重新整理,才會看到後來丟進去的資料

涉及HackMD筆記


參考的其他技術文章

-Dswt.enable.autoScale=true
-Dswt.autoScale=140 //原文的200會讓Swing JFrame製作工具預覽區變太大
-Dswt.autoScale.method=nearest


然而我旋即發現雖然Swing製作工具預覽區大小趨於實際jdk比例,但撰寫程式的地方卻破圖了,還變得容易當機
應該是我使用的主題跟這個設定有衝突,我後來還是將就使用讓系統覆寫dpi的方式,選擇系統(增強)會比較清晰一點,但有些按鈕會有消失的Bug


  • 如何切換程式樣式風格
    • 另外美化過程中不使用預設工具給的顏色,改成自己輸入感覺還是不夠的…但要做輸入框圓角化處理、改變視窗樣式等,由於建置工具老舊,方法會比較土炮一點,以上因為不是本次作業的重點(連接資料庫),所以暫時不深入
    • 上圖可見我放入的素材圖片均呈鋸齒狀,疑似是我個人電腦的異常狀況,其他電腦不一定有這個現象。