JAVA MVC_以MVC架構來進行Java GUI程式開發(一)_介面層邏輯和業務層邏輯的拆分




JAVA MVC架構實作

在一些現今程式應用中
很常聽到和使用到的MVC(Model-View-Controller)
最早於1978年的 特里夫·林斯高格  (Trygve Reenskaug)  所提出的軟體工程三層架構

其主張介面層邏輯要跟業務層邏輯分離
不應該混在一塊

使程式各自類可以各司其職(符合單一職責原則)
利於後續程式增多後的維護






Model : 負責儲存及維護一些來自前端使用者介面資料的流程邏輯
(使用者輸入了資料後進行捨麼計算....)

View : 舉凡使用者和前端介面互動的相關流程邏輯接歸屬於View來做控制
(捨麼時候要跳窗,當按下捨麼按鈕做....)

Controller : 介於Model和View兩者之間的溝通橋樑
主要接收View使用者於前端介面的資料後再傳遞給Model並接收來自Model回傳結果
再丟還給View進行介面渲染(更新顯示)的流程。


這樣就不會於系統維護到後期時發生
因為過去都將Model  data處理邏輯部分的Code內嵌至View而造成的
因為後續有需要用多個不同的View要來顯示某些同一資料部分
而導致出現重複黏貼Model data code 處理的區塊



開發規格與工具




新增好專案後


建置好三個java package



資源package下存著一張400*200的底圖


針對View 新增一個繼承JFrame的可視化class 及設計面板




首先將預設新增的View JFrame中進入點程式移動至main中
於此的main區塊可先暫時註解掉(留著做針對該類中的 unit test也可以)
程式運行時會自動找main進入點於哪個class的java檔案去運行


針對View 類別
起初預設的程式碼
我們進行介面端的邏輯設計規劃


Defalt View.java


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kuanyu.view;

/**
 *
 * @author chous
 */
public class View extends javax.swing.JFrame {

    /**
     * Creates new form View
     */
    public View() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>                        



    // Variables declaration - do not modify                     
    // End of variables declaration                   
}

針對JFrame Form設置






在View Form上拖曳一個JPanel  (先保有後續調動的彈性不要直接在Form上設置)


JPanel的設置


設置完寬高後會發現沒有自動對齊


這時可以往上拖曳會自動做類似WinForm當中的介面屬性  Dock -> Fill

這裡會發現寬高的即時呈現跑掉
在去改為Default即可



於JPanel上設置AbsoluteLayout (會依以所想要的絕對座標位置來安排)









大致上把前端控制項位置布局完成



JLabel(for  底圖載入)


MVC當中的 Model起手式

Model package添加完後再新建Model.java

Model.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * and open the template in the editor.
 */
package com.kuanyu.model;

/**
 *
 * @author chous
 */
public class Model {
    private String name;

    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    //toString()  overrite
    @Override
    public String toString() {
        return "Model{" + "name=" + name + '}';
    }
    
}

此段功能之單元測試




MVC 當中的View起手式


針對 View.java先完成初步的程式撰寫

UI 初始化時位置
當UI被拖曳時位置移動更新 (先點擊取得UI位置 再滑鼠拖曳按著不放移動並更新位置)
UI關閉事件

View.java

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kuanyu.view;

import java.awt.Toolkit;

/**
 *
 * @author chous
 */
public class View extends javax.swing.JFrame {

    private int MouseX;
    private int MouseY;

    private int x , screenW;
    private int y , screenH;

    /**
     * Creates new form View Set location center
     * https://codingnote.blogspot.com/2008/04/java.html
     */
    public View() {
        initComponents();
        this.setLocationRelativeTo(null);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        lblClose = new javax.swing.JLabel();
        lblName = new javax.swing.JLabel();
        txtName = new javax.swing.JTextField();
        btnEnter = new javax.swing.JButton();
        btnClear = new javax.swing.JButton();
        lblResult = new javax.swing.JLabel();
        lblBG = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        setUndecorated(true);
        setPreferredSize(new java.awt.Dimension(400, 200));
        setResizable(false);

        jPanel1.setMinimumSize(new java.awt.Dimension(400, 200));
        jPanel1.setPreferredSize(new java.awt.Dimension(400, 200));
        jPanel1.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

        lblClose.setFont(new java.awt.Font("新細明體", 1, 18)); // NOI18N
        lblClose.setForeground(new java.awt.Color(0, 0, 204));
        lblClose.setText("X");
        lblClose.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                lblCloseMouseClicked(evt);
            }
        });
        jPanel1.add(lblClose, new org.netbeans.lib.awtextra.AbsoluteConstraints(380, 0, -1, -1));

        lblName.setText("Enter your name:");
        jPanel1.add(lblName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 40, -1, -1));
        lblName.getAccessibleContext().setAccessibleName("");

        jPanel1.add(txtName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 70, 190, -1));

        btnEnter.setText("ENTER");
        jPanel1.add(btnEnter, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 40, -1, -1));

        btnClear.setText("CLEAR");
        jPanel1.add(btnClear, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 90, -1, -1));

        lblResult.setText("_____");
        jPanel1.add(lblResult, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 110, -1, -1));

        lblBG.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/kuanyu/resources/bg.png"))); // NOI18N
        lblBG.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                lblBGMouseDragged(evt);
            }
        });
        lblBG.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                lblBGMousePressed(evt);
            }
        });
        jPanel1.add(lblBG, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 0, -1, -1));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>                        


    
    
    private void lblBGMouseDragged(java.awt.event.MouseEvent evt) {                                   
        // TODO add your handling code here:
        int x = evt.getXOnScreen();
        int y = evt.getYOnScreen();
        this.setLocation(x - MouseX, y - MouseY);
    }                                  

    private void lblBGMousePressed(java.awt.event.MouseEvent evt) {                                   
        // TODO add your handling code here:
        MouseX = evt.getX();
        MouseY = evt.getY();
    }                                  

    private void lblCloseMouseClicked(java.awt.event.MouseEvent evt) {                                      
        // TODO add your handling code here:
        System.exit(0);
    }                                     


    // Variables declaration - do not modify                     
    private javax.swing.JButton btnClear;
    private javax.swing.JButton btnEnter;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JLabel lblBG;
    private javax.swing.JLabel lblClose;
    private javax.swing.JLabel lblName;
    private javax.swing.JLabel lblResult;
    private javax.swing.JTextField txtName;
    // End of variables declaration                   

}






MVC 當中的Controller起手式

我們說 Controller是 View 以及  Model兩者之間的溝通中介
在定義完對應物件屬性後
進行Ctrl + Shift + I 可自動做缺失對應Package的 import


這裡我們要在main主程式進入點地方
去實體化我們的Controller時  傳入 model , view
因此定義我們的建構子






將原本main主程式區塊稍稍改寫成呼Controller的版本

於Controller中再去針對呼叫的View參數去做面板顯示


最後大致補上一些中介層 View和Model溝通傳輸資料
相關事件即可

Controller.java


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kuanyu.controller;

import com.kuanyu.model.Model;
import com.kuanyu.view.View;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;

/**
 *
 * @author chous
 */
public class Controller implements ActionListener {

    private Model m;
    private View v;

    //Constructor
    public Controller(Model m, View v) {
        this.m = m;
        this.v = v;
        this.v.setVisible(true);

        //Set Action Commands
        this.v.getBtnEnter().setActionCommand("ENTER");
        this.v.getBtnClear().setActionCommand("CLEAR");
        //Add Action Listener
        this.v.getBtnEnter().addActionListener(this);
        this.v.getBtnClear().addActionListener(this);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        switch (command) {
            case "ENTER":
                System.out.println("Enter....");
                String name = v.getTxtName().getText();
                System.out.println(name);
                if (!name.equals("")) {
                    m.setName(name);
                    //Send objects from the Model section to View section
                    v.showResult(m);
                    v.getTxtName().setText("");
                } else {
                    JOptionPane.showMessageDialog(v, "不可為空", "輸入錯誤", 0);
                }
                break;
            case "CLEAR":
                System.out.println("Clear....");
                v.getTxtName().setText("");
                v.getLblResult().setText("");
                break;
        }
    }
}


最後版的
View.java


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kuanyu.view;

import com.kuanyu.model.Model;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTextField;

/**
 *
 * @author chous
 */
public class View extends javax.swing.JFrame {

    private int MouseX;
    private int MouseY;

    private int x , screenW;
    private int y , screenH;

    /**
     * Creates new form View Set location center
     * https://codingnote.blogspot.com/2008/04/java.html
     */
    public View() {
        initComponents();
        this.setLocationRelativeTo(null);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        lblClose = new javax.swing.JLabel();
        lblName = new javax.swing.JLabel();
        txtName = new javax.swing.JTextField();
        btnEnter = new javax.swing.JButton();
        btnClear = new javax.swing.JButton();
        lblResult = new javax.swing.JLabel();
        lblBG = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        setUndecorated(true);
        setPreferredSize(new java.awt.Dimension(400, 200));
        setResizable(false);

        jPanel1.setMinimumSize(new java.awt.Dimension(400, 200));
        jPanel1.setPreferredSize(new java.awt.Dimension(400, 200));
        jPanel1.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

        lblClose.setFont(new java.awt.Font("新細明體", 1, 18)); // NOI18N
        lblClose.setForeground(new java.awt.Color(0, 0, 204));
        lblClose.setText("X");
        lblClose.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                lblCloseMouseClicked(evt);
            }
        });
        jPanel1.add(lblClose, new org.netbeans.lib.awtextra.AbsoluteConstraints(380, 0, -1, -1));

        lblName.setText("Enter your name:");
        jPanel1.add(lblName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 40, -1, -1));
        lblName.getAccessibleContext().setAccessibleName("");

        jPanel1.add(txtName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 70, 190, -1));

        btnEnter.setText("ENTER");
        jPanel1.add(btnEnter, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 40, -1, -1));

        btnClear.setText("CLEAR");
        jPanel1.add(btnClear, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 90, -1, -1));

        lblResult.setText("_____");
        jPanel1.add(lblResult, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 110, -1, -1));

        lblBG.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/kuanyu/resources/bg.png"))); // NOI18N
        lblBG.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                lblBGMouseDragged(evt);
            }
        });
        lblBG.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                lblBGMousePressed(evt);
            }
        });
        jPanel1.add(lblBG, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 0, -1, -1));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>                        
    
    //Getter for Cnntroller using
    public JButton getBtnClear() {
        return btnClear;
    }

    public JButton getBtnEnter() {
        return btnEnter;
    }

    public JLabel getLblResult() {
        return lblResult;
    }

    public JTextField getTxtName() {
        return txtName;
    }
    //Getter for Cnntroller using
    
    public void showResult(Model m){
        lblResult.setText("Hi !! " + m.getName() 
                + " This is MVC test");
    }
    
    
    private void lblBGMouseDragged(java.awt.event.MouseEvent evt) {                                   
        // TODO add your handling code here:
        int x = evt.getXOnScreen();
        int y = evt.getYOnScreen();
        this.setLocation(x - MouseX, y - MouseY);
    }                                  

    private void lblBGMousePressed(java.awt.event.MouseEvent evt) {                                   
        // TODO add your handling code here:
        MouseX = evt.getX();
        MouseY = evt.getY();
    }                                  

    private void lblCloseMouseClicked(java.awt.event.MouseEvent evt) {                                      
        // TODO add your handling code here:
        System.exit(0);
    }                                     


    // Variables declaration - do not modify                     
    private javax.swing.JButton btnClear;
    private javax.swing.JButton btnEnter;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JLabel lblBG;
    private javax.swing.JLabel lblClose;
    private javax.swing.JLabel lblName;
    private javax.swing.JLabel lblResult;
    private javax.swing.JTextField txtName;
    // End of variables declaration                   

}












Reference link:
https://www.javacodegeeks.com/2017/09/mvc-delivery-mechanism-domain-model.html

留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header