使用Java与MySQL开发计算器

发布时间 2023-11-21 12:31:24作者: 苟小兵

[实验目的]

1.掌握软件开发的基本流程

2.掌握常用的软件开发方式和工具。

[实验内容]

设计一个包含登录界面的计算器软件,该软件可以实现第一次作业中的全部功能,同时可以保存用户的历史计算记录(保存数据最好使用数据库)。

[实验环境及开发工具]

  1. 使用Microsoft Visio作绘图工具
  2. 使用Java语言与IntelliJ IDEA Community Edition作开发工具
  3. 使用MySQL数据库储存数据
  4. 使用JDBC链接数据库

[流程图]

1、登录流程图:

2、注册流程图:

[界面]

1、登录界面

2、注册界面

3、计算器界面

[测试]

1、登录失败

2、登录成功

3、注册失败

4、注册成功

5、数据库存储登录信息及计算记录

[代码]

1、登录注册代码

①Login类:封装登录所用属性及方法

package User;

public class Login {
    String id;
    String password;
    LoginDemo loginDemo;
    boolean loginSuccess = false;
    public void setLoginDemo(LoginDemo loginDemo) {
        this.loginDemo = loginDemo;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public boolean isLoginSuccess() {
        return loginSuccess;
    }

    public void setLoginSuccess(boolean loginSuccess) {
        this.loginSuccess = loginSuccess;
    }
}

②LoginDemo类:登录UI设计

package User;

import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.plaf.basic.BasicPanelUI;
import java.awt.*;
import java.sql.SQLException;


public class LoginDemo extends JFrame {
    public LoginDemo() {
        super("计算器登录");
        //获取显示屏的大小
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int sw = screenSize.width;
        int sh = screenSize.height;
        //设置窗口的位置
        int width = 300;
        int height = 340;
        this.setBounds((sw - width) / 2, (sh - height) / 2, width, height);

//      盒子模块
        Box ubox = Box.createHorizontalBox();
        Box pbox = Box.createHorizontalBox();
        Box vbox = Box.createVerticalBox();

        JLabel uLabel = new JLabel("  I   d  :");
        JTextField uField = new JTextField();

        JLabel pLabel = new JLabel("密  码:");
        JPasswordField pFd = new JPasswordField();
        pFd.setColumns(16);
        pFd.setEchoChar('●');

        JButton button1 = new JButton("登录");
        button1.setToolTipText("登录");
        JButton button2 = new JButton("重置");
        button2.setToolTipText("重置");
        JMenu Menubutton3 = new JMenu("注册账号");
        Menubutton3.setToolTipText("注册账号");

        button1.setBounds((this.getWidth() - 120 - 180) / 2, 250, 100, 30);
        button1.setCursor(new Cursor(Cursor.HAND_CURSOR));

        button2.setBounds((this.getWidth() - 120 + 180) / 2, 250, 100, 30);


        Menubutton3.setUI(new BasicButtonUI());
        Menubutton3.setBounds(5, 280, 85, 20);


        //小盒子,设计用户名模块
        ubox.add(uLabel);
        ubox.add(Box.createHorizontalStrut(5));
        ubox.add(uField);
        //小盒子,设计密码模块
        pbox.add(pLabel);
        pbox.add(Box.createHorizontalStrut(5));
        pbox.add(pFd);

        //大盒子
        vbox.add(Box.createVerticalStrut(80));
        vbox.add(ubox);
        vbox.add(Box.createVerticalStrut(60));
        vbox.add(pbox);

        JPanel panel = new JPanel();
        panel.setUI(new BasicPanelUI());
        panel.setOpaque(false);
        panel.add(vbox, BorderLayout.CENTER);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        button1.addActionListener(e -> {
            try {
                init(this,uField, pFd);
            } catch (Exception exception) {
                JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE);
            }
        });
        button2.addActionListener(e -> {
            uField.setText("");
            pFd.setText("");
        });
        Menubutton3.addActionListener(e -> {
            try {
                this.dispose();
                Thread.sleep(1000);
                new RegisterDemo();
            } catch (InterruptedException interruptedException) {
                JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE);
            }
        });

        this.add(button1);
        this.add(button2);
        this.add(Menubutton3);
        this.add(panel);
        this.setVisible(true);
        this.setResizable(false);
    }

    public void init(LoginDemo loginDemo,JTextField uField, JPasswordField pFd) {
        Login login;
        UserLogin UserLogin;
        try {
            login=new Login();
            login.setLoginDemo(loginDemo);
            login.setId(uField.getText());
            char[] p = pFd.getPassword();
            login.setPassword(new String(p));
            UserLogin = new UserLogin();
            UserLogin.readLogin(login);
        } catch (SQLException | ClassNotFoundException e) {
            JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE);
        }

    }
}

③UserLogin类:用户登录且链接数据库

package User;
import com.mysql.cj.jdbc.MysqlDataSource;

import com.auqa.version.calculator;

import javax.swing.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UserLogin {
    Connection connection = null;
    PreparedStatement prepare;
    ResultSet resultSet;
    boolean loginSuccess;

    public UserLogin() throws SQLException, ClassNotFoundException {

        try {
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("123456");
            connection = mysqlDataSource.getConnection();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "数据库连接失败", "提示", JOptionPane.WARNING_MESSAGE);
        }
    }
    public void readLogin(Login login) {
        try {
            String sql = "SELECT * FROM test.User WHERE Id = ? AND  Password = ?";
            prepare = connection.prepareStatement(sql);
            String id = login.getId();
            prepare.setString(1, id);
            prepare.setString(2, login.getPassword());
            resultSet = prepare.executeQuery();
            if (resultSet.next()) {
                login.setLoginSuccess(true);
                JOptionPane.showMessageDialog(null, "登录成功");
                new calculator(id);
            } else {
                login.setLoginSuccess(false);
                if (login.getId().isEmpty() || login.getPassword().isEmpty()) {
                    if (login.getId().isEmpty()) {
                        JOptionPane.showMessageDialog(null, "ID不能为空!", "提示", JOptionPane.WARNING_MESSAGE);
                    }
                    if (login.getPassword().isEmpty()){
                        JOptionPane.showMessageDialog(null, "密码不能为空!","提示", JOptionPane.WARNING_MESSAGE);
                    }
                }else{
                    JOptionPane.showMessageDialog(null, "登录失败", "警告", JOptionPane.ERROR_MESSAGE);
                }
            }
            connection.close();
            loginSuccess = login.isLoginSuccess();
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.ERROR_MESSAGE);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

④Register类:封装注册所用属性方法

package User;
//注册模型
public class Register {
    String name;
    String id;
    String password;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

⑤RegisterDemo类:注册UI设计及判断注册信息

package User;

import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.plaf.basic.BasicPanelUI;
import java.awt.*;
import java.sql.SQLException;

class RegisterDemo extends JFrame {
    public RegisterDemo() {
        //获取显示屏的大小
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int sw = screenSize.width;
        int sh = screenSize.height;
        //设置窗口的位置
        int width = 500;
        int height = 600;
        this.setBounds((sw - width) / 2, (sh - height) / 2, width, height);
        this.setTitle("注册");

        //盒子模块
        Box namebox = Box.createHorizontalBox();
        Box ubox = Box.createHorizontalBox();
        Box pbox = Box.createHorizontalBox();
        Box repbox = Box.createHorizontalBox();
        Box vbox = Box.createVerticalBox();

        JLabel nameLabel = new JLabel("  用户名 :");
        JTextField nameField = new JTextField();

        JLabel uLabel = new JLabel("     I    d   :");
        JTextField uField = new JTextField();

        JLabel pLabel = new JLabel("密       码:");
        JPasswordField pFd = new JPasswordField();
        pFd.setColumns(16);
        pFd.setEchoChar('●');

        JLabel RepLabel = new JLabel("确认密码:");
        JPasswordField RepFd = new JPasswordField();
        RepFd.setColumns(16);
        RepFd.setEchoChar('●');

        JButton button1 = new JButton("注册");
        button1.setToolTipText("注册");
        JButton button2 = new JButton("重置");
        button2.setToolTipText("重置");
        JMenu Menubutton3 = new JMenu("返回登录");
        Menubutton3.setToolTipText("返回登录");

        button1.setBounds((this.getWidth() - 120 - 180) / 2, this.getHeight() - 150, 120, 30);
        button2.setBounds((this.getWidth() - 120 + 180) / 2, this.getHeight() - 150, 120, 30);

        Menubutton3.setUI(new BasicButtonUI());
        Menubutton3.setBounds(5, this.getHeight() - 70, 85, 20);


        namebox.add(nameLabel);
        namebox.add(Box.createHorizontalStrut(5));
        namebox.add(nameField);
        //小盒子,设计用户名模块
        ubox.add(uLabel);
        ubox.add(Box.createHorizontalStrut(5));
        ubox.add(uField);
        //小盒子,设计密码模块
        pbox.add(pLabel);
        pbox.add(Box.createHorizontalStrut(5));
        pbox.add(pFd);

        repbox.add(RepLabel);
        repbox.add(Box.createHorizontalStrut(5));
        repbox.add(RepFd);

        //大盒子
        vbox.add(Box.createVerticalStrut(90));
        vbox.add(namebox);
        vbox.add(Box.createVerticalStrut(65));
        vbox.add(ubox);
        vbox.add(Box.createVerticalStrut(65));
        vbox.add(pbox);
        vbox.add(Box.createVerticalStrut(65));
        vbox.add(repbox);

        //转换
        JPanel panel = new JPanel();
        panel.setUI(new BasicPanelUI());
        panel.setOpaque(false);
        panel.add(vbox, BorderLayout.CENTER);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        button1.addActionListener(e -> {
            String pField = new String(pFd.getPassword());
            String repField = new String(RepFd.getPassword());
            try {
                if (nameField.getText().isEmpty() || pField.isEmpty() || repField.isEmpty()||uField.getText().isEmpty()) {
                    if (nameField.getText().isEmpty()) {
                        JOptionPane.showMessageDialog(null, "用户名不能为空", "提示", JOptionPane.WARNING_MESSAGE);
                    } else if(uField.getText().isEmpty()){
                        JOptionPane.showMessageDialog(null, "ID号不能为空", "提示", JOptionPane.WARNING_MESSAGE);
                    }
                    else if (pField.isEmpty()) {
                        JOptionPane.showMessageDialog(null, "密码不能为空", "提示", JOptionPane.WARNING_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(null, "确认密码不能为空", "提示", JOptionPane.WARNING_MESSAGE);
                    }
                } else {
                    if (!pField.equals(repField)) {
                        JOptionPane.showMessageDialog(null, "两次密码不一致", "提示", JOptionPane.WARNING_MESSAGE);
                    } else {
                        init(nameField,uField, pFd);
                    }
                }

            } catch (Exception exception) {
                JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE);
            }
        });
        button2.addActionListener(e -> {
            nameField.setText(null);
            uField.setText(null);
            pFd.setText(null);
            RepFd.setText(null);
        });
        Menubutton3.addActionListener(e -> {
            try {
                this.dispose();
                Thread.sleep(1000);
                new LoginDemo();
            } catch (Exception exception) {
                JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE);
            }
        });
        this.add(button1);
        this.add(button2);
        this.add(Menubutton3);
        this.add(panel);
        this.setVisible(true);
        this.setResizable(false);
    }
    public void init(JTextField nameField,JTextField uField, JPasswordField pFd) {
        Register register;
        UserRegister userRegister;
        try {
            register = new Register();
            register.setName(nameField.getText());
            register.setId(uField.getText());
            char[] p1 = pFd.getPassword();
            register.setPassword(new String(p1));
            userRegister = new UserRegister();
            userRegister.writeRegister(register);
            uField.setText(null);
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(null, "异常", "警告", JOptionPane.WARNING_MESSAGE);
        }
    }
}

⑥UserRegister类:用户注册及链接数据库

package User;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.swing.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class UserRegister {
    Connection connection = null;
    PreparedStatement presql;

    public UserRegister() throws SQLException {
        try {
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("123456");
            connection = mysqlDataSource.getConnection();
        } catch (SQLException throwables) {
            JOptionPane.showMessageDialog(null,"数据库连接失败","警告",JOptionPane.WARNING_MESSAGE);
        }
    }
    public void writeRegister(Register register){
        int flag;
        try {
            String sql = "INSERT INTO test.User VALUES (?,?,?)";
            presql = connection.prepareStatement(sql);
            presql.setString(1,register.getId());
            presql.setString(2,register.getPassword());
            presql.setString(3,register.getName());
            flag = presql.executeUpdate();
            connection.close();
            if (flag!=0){
                JOptionPane.showMessageDialog(null,"注册成功");
            }else {
                JOptionPane.showMessageDialog(null,"注册失败","提示",JOptionPane.WARNING_MESSAGE);
            }
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(null,"ID已存在!","警告",JOptionPane.WARNING_MESSAGE);
        }

    }
}

2、计算器代码

①calculate类:计算器运算

package POJO;


import java.math.BigDecimal;
import java.util.Stack;


public class calculate {

    // 符号栈
    private Stack<String> signStack = new Stack();

    // 数字栈
    private Stack<BigDecimal> numStack = new Stack();


    /*******************************************将军的恩情还不完*************************************************/


    // 额switch可以判断引用类型变量的值相等吗{0:'+', 1:'-', 2:'x', 3:'/'}
    private static final String signCode = "+-x/()";

    // 计算器主体模块
    public BigDecimal work(BigDecimal caled, BigDecimal cal, String sign) {
        BigDecimal ans = null;
        switch (signCode.indexOf(sign)) {
            case 0:
                ans = caled.add(cal);
                break;
            case 1:
                ans = caled.subtract(cal);
                break;
            case 2:
                ans = caled.multiply(cal);
                break;
            case 3:
                try {
                    ans = caled.divide(cal);
                }catch (ArithmeticException AE) {
                    if(AE.getLocalizedMessage().equals("Non-terminating decimal expansion; no exact representable decimal result."))
                        ans = caled.divide(cal, 5, BigDecimal.ROUND_HALF_UP);
                    else
                        ans = BigDecimal.valueOf(32202);
                    System.out.println("Exception : "+AE.getLocalizedMessage());
                }
                break;
            case 4:
            case 5:
                this.numStack.push(caled);
                ans = cal;
                break;
            default:
                ans = null;
        }
        return ans;
    }

    // 设计开方(牛顿莱布尼兹)
    public static BigDecimal niuton(BigDecimal caled) {
        BigDecimal ans;
        if (caled.doubleValue() < 0) {
            System.out.println("Exception : Negative caled");
            return BigDecimal.valueOf(32202);
        }
        double x = 1;
        double y = x - (x * x - caled.doubleValue()) / (2 * x);
        while (x - y > 0.00000001 || x - y < -0.00000001) {
            x = y;
            y = x - (x * x - caled.doubleValue()) / (2 * x);
        }
        ans = BigDecimal.valueOf(y);
        return ans;
    }

    // 设计平方
    public static BigDecimal square(BigDecimal caled) {
        return caled.pow(2);
    }

    // 设计清屏
    public void refresh() {
        this.numStack.clear();
        this.signStack.clear();
        this.signStack.push("=");
        // 解决计算当(x+y)后输入符号时,需要出栈两个数进行括号运算(即将数按顺序压回去)时数字栈只有一个栈的问题。
        this.numStack.push(new BigDecimal(0));
    }


    /**********************************************入集中营**************************************************/

    // 索引,见详细设计
    private String index = "+-x/()=";

    // 数据,见详细设计^^_  ,>为0,<为1,=为2,null为3
    private int[][] compareToSign = {{0, 0, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 1, 0, 0},
            {0, 0, 0, 0, 1, 0, 0}, {1, 1, 1, 1, 1, 2, 3}, {0, 0, 0, 0, 3, 0, 0}, {1, 1, 1, 1, 1, 3, 2}};


    // 数字入栈
    public void numPush(String decimal) {
        this.numStack.push(new BigDecimal(decimal));
    }

    public void numPush(BigDecimal decimal) {
        this.numStack.push(decimal);
    }


    // 控制流,详细见详细设计p1
    public void calIOC(String topSign) {
        BigDecimal caled, cal;
        String temp;
        temp = this.signStack.peek();
        switch (this.compareToSign[index.indexOf(temp)][index.indexOf(topSign)]) {
            case 0:
                cal = this.numStack.pop();
                caled = this.numStack.pop();
                temp = this.signStack.pop();
                this.numStack.push(this.work(caled, cal, temp));
                this.signStack.push(topSign);
                break;
            case 1:
                this.signStack.push(topSign);
                break;
            case 2:
                this.signStack.pop();
                break;
            default:
                System.out.println("Exception : wrong I/O");
                break;
        }
    }


    // 等号入栈
    public BigDecimal equaIOC() {
        BigDecimal ans, caled, cal;
        String topSign;
        while (!"=".equals(this.signStack.peek())) {
            topSign = this.signStack.pop();
            cal = this.numStack.pop();
            caled = this.numStack.pop();
            this.numStack.push(this.work(caled, cal, topSign));
        }
        ans = this.numStack.pop();
        return ans;
    }

    // pow的IO流控制
    public void powIOC(String topSign) {
        BigDecimal temp;
        temp = this.numStack.pop();
        if (topSign.equals("^2")) {
            this.numStack.push(calculate.square(temp));
        } else {
            this.numStack.push(calculate.niuton(temp));
        }
    }

    // 通过循环执行运算功能直到左括号为栈顶符号来规避括号内有运算符
    public void barcketIOC() {
        BigDecimal caled, cal;
        String topSign;
        while (!"(".equals(this.signStack.peek())) {
            topSign = this.signStack.pop();
            cal = this.numStack.pop();
            caled = this.numStack.pop();
            this.numStack.push(this.work(caled, cal, topSign));
        }
        this.signStack.pop();
    }


}

②calculator类:计算器UI设计(基于上次小组作业,添加变量存储计算器计算过程级结果)

package com.auqa.version;

// 导入自己的计算类

import POJO.calculate;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.sql.SQLException;

// 计算器界面
public class calculator extends JFrame implements ActionListener {
    Records rec = new Records();

    // 获得显示屏大小
    public static final int SCREAM_HEIGHT = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
    // 根据显示屏高度设定计算器界面大小
    private static final int EXAMPLE = (int) (SCREAM_HEIGHT / 4.32);


    // 字体大小
    Font cu = new Font("粗体", Font.BOLD, (int) (EXAMPLE * 0.2));


    /**********************************************超级初始化块*******************************************************/


    protected void __init__() {
        // 设置窗口名称
        this.setTitle("计算器");
        // 4比3固定窗口
        this.setSize(EXAMPLE * 3, EXAMPLE * 4);
        this.setResizable(false);
        this.setLocationRelativeTo(null);
        // 设置窗口可见
        this.setVisible(true);
        this.setBackground(Color.black);
        // 设置关闭按钮(释放进程)
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        // 设置方向布局
        this.setLayout(new BorderLayout());
    }


    /**********************************************北国风光*******************************************************/

    // 北面组件
    private JPanel northBox = new JPanel(new FlowLayout());
    private JTextField input = new JTextField();
    private JButton clear = new JButton();


    // 设置北面组件
    private void setNorth() {
        // 设置数字栏
        this.input.setPreferredSize(new Dimension((int) (EXAMPLE * 2.2), (int) (EXAMPLE * 0.4)));
        this.input.setFont(this.cu);
        this.input.setForeground(Color.BLACK);      // 额好像没用,但限制用户输入更重要
        this.input.setEnabled(false);
        this.input.setHorizontalAlignment(SwingConstants.RIGHT);

        // 设置清空
        this.clear.setText("C");
        this.clear.setPreferredSize(new Dimension((int) (EXAMPLE * 0.4), (int) (EXAMPLE * 0.4)));
        this.clear.setFont(this.cu);
        this.clear.setForeground(Color.RED);

        // 安装北仪表
        this.northBox.add(this.input);
        this.northBox.add(this.clear);

        // 安装北仪表到主体
        this.add(this.northBox, BorderLayout.NORTH);
    }


    /**********************************************中央处理器*******************************************************/


    // 中部组件
    private JPanel CPU = new JPanel();
    private JButton[] cal = new JButton[20];
    // 后16个按钮顺序,懒得写集合类了
    String str = "789/456x123-0.=+";

    // 设置中部组件
    private void setCenter() {
        // 划分20格
        this.CPU.setLayout(new GridLayout(5, 4));
        // 设置开方按钮
        this.cal[0] = new JButton();
        this.cal[0].setText("^-2");
        this.cal[0].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15)));
        this.cal[0].setFont(this.cu);
        this.cal[0].setForeground(Color.BLUE);
        // 设置括号按钮
        this.cal[1] = new JButton();
        this.cal[1].setText("^2");
        this.cal[1].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15)));
        this.cal[1].setFont(this.cu);
        this.cal[1].setForeground(Color.BLUE);
        this.cal[2] = new JButton();
        this.cal[2].setText("(");
        this.cal[2].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15)));
        this.cal[2].setFont(this.cu);
        this.cal[2].setForeground(Color.BLUE);

        // 设置清除按钮
        this.cal[3] = new JButton();
        this.cal[3].setText(")");
        this.cal[3].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15)));
        this.cal[3].setFont(this.cu);
        this.cal[3].setForeground(Color.BLUE);

        // 设置后16个按钮
        for (int i = 4; i < 20; i++) {
            String temp = this.str.substring(i - 4, i - 3);
            this.cal[i] = new JButton();
            this.cal[i].setText(temp);
            this.cal[i].setPreferredSize(new Dimension((int) (EXAMPLE * 0.2), (int) (EXAMPLE * 0.15)));
            this.cal[i].setFont(this.cu);
            if ("+-x/=".contains(temp)) {
                this.cal[i].setForeground(Color.GRAY);
            }
        }
        // 添加按钮
        for (int i = 0; i < 20; i++) {
            this.CPU.add(this.cal[i]);
        }
        this.add(this.CPU,BorderLayout.CENTER);
    }


    /********************************************** 南柯一梦 *******************************************************/

    public String uid;

    public void setUid(String id) {
        this.uid = id;
    }

    // 南面组件
    private JLabel message = new JLabel("welcome,", SwingConstants.CENTER);

    // 设置南面组件
    private void setSouth() {
        this.message.setText("welcome," + this.uid);
        this.message.setPreferredSize(new Dimension((int) (EXAMPLE * 0.1), (int) (EXAMPLE * 0.1)));
        this.message.setForeground(Color.BLACK);
        this.add(this.message, BorderLayout.SOUTH);
    }


    /*********************************************监听*********************************************************/

    // 给按钮添加监听
    private void setListener() {
        for (JButton j : cal) {
            j.addActionListener(this);
        }
        this.clear.addActionListener(this);
    }

    // 监听事件设置
    @Override
    public void actionPerformed(ActionEvent e) {
        String listen = e.getActionCommand();
        if ("0.1^23456789+-x/()^-2".contains(listen)) {
            this.input.setText(this.input.getText() + listen);
        }
        this.bigWork(listen);
    }


    /*****************************************状态**************************************************/

    // 小数点信号
    private Boolean pointSignal = false;
    // 括号信号
    private int barcketNum = 0;

    private String num = "0123456789";
    private String sign = "+-x/(";

    // 输入的最后一位为数字时的状态,详细见详细设计表格
    public void inNum() {
        // 只能输入pow函数,右括号,数字和符号按钮,不能输入左括号,若小数点信号为真,则可以输入小数点
        for (int i=0;i<20;i++) {
            if("(".equals(this.cal[i].getText())) {
                this.cal[i].setEnabled(false);
            }
            else {
                this.cal[i].setEnabled(true);
            }
        }
        // 根据信号设置
        this.cal[17].setEnabled(this.pointSignal);
    }

    // 输入的最后一位为符号或左括号时
    public void inSign() {
        // 只能输入非小数点数字及左括号,小数点信号开启
        for (int i=0;i<20;i++) {
            if("(".equals(this.cal[i].getText()) || this.num.contains(this.cal[i].getText())) {
                this.cal[i].setEnabled(true);
            }
            else {
                this.cal[i].setEnabled(false);
            }
        }
        this.pointSignal = true;
    }

    // 输入最后一位为右括号或pow运算时
    public void inPow() {
        // 只能输入符号和右括号和pow函数
        for (int i=0;i<20;i++) {
            if("(".equals(this.cal[i].getText()) || this.num.contains(this.cal[i].getText()) || ".".equals(this.cal[i].getText())) {
                this.cal[i].setEnabled(false);
            }
            else {
                this.cal[i].setEnabled(true);
            }
        }
    }

    // 输入最后一位为小数点时
    public void inPoint() {
        // 只能输入非小数点数字,小数点信号关闭
        for (int i=0;i<20;i++) {
            if(this.num.contains(this.cal[i].getText())) {
                this.cal[i].setEnabled(true);
            }
            else {
                this.cal[i].setEnabled(false);
            }
        }
        this.pointSignal = false;
    }

    public void inEqual() {
        for (int i=0;i<20;i++) {
            this.cal[i].setEnabled(false);
        }
    }


    /*****************************************核酸隔离点*********************************************/


    // 真正的超级初始化块
    public calculator() throws HeadlessException, SQLException, ClassNotFoundException {
        // 界面设置
        this.__init__();
        this.setNorth();
        this.setCenter();
        this.setSouth();
        // 交互设置
        this.setListener();
        JOptionPane.showMessageDialog(this, "由于框架原因,本计算器打开时可能按钮显示不全,请最小化后打开");
        this.inSign();
        this.calculate.refresh();
    }

    calculate calculate = new calculate();
    private String temStr = "";

    // 记录公式及答案为后续拓展提供api
    private String records;
    private String result;

    public void setCaled(String caled) {
        this.records = caled;
    }

    public void setAns(BigDecimal ans) {
        this.result = ans.toString();
    }

    public String getCaled() {
        return records;
    }

    public String getAns() {
        return result;
    }


    // 控制器
    public void bigWork(String listen) {
        
        // 记录括号信号
        if ("(".equals(listen)) {
            this.barcketNum++;
        }
        if (")".equals(listen)) {
            this.barcketNum--;
        }


        // 基础状体转换
        if (this.num.contains(listen)) {
            this.temStr = this.temStr +listen;
            this.inNum();
        } else if (this.sign.contains(listen)) {
            if(!"".equals(temStr)) {
                this.calculate.numPush(this.temStr);
                this.temStr = "";
            }
            this.calculate.calIOC(listen);
            this.inSign();
        } else if (")".equals(listen) || listen.contains("^")) {
            if(!"".equals(temStr)) {
                this.calculate.numPush(this.temStr);
                this.temStr = "";
            }
            if (listen.contains("^")) {
                calculate.powIOC(listen);
            } else {
                this.calculate.barcketIOC();
            }
            this.inPow();
        } else if (".".equals(listen)) {
            this.temStr = this.temStr +listen;
            this.inPoint();
        }  else if ("=".equals(listen)) {
            if(!"".equals(temStr)) {
                this.calculate.numPush(this.temStr);
                this.temStr = "";
            }
            this.setCaled(this.input.getText());
            this.setAns(this.calculate.equaIOC());
            try {
                rec.excuteins(uid,records,result);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            this.input.setText(this.result);
            this.inEqual();
        }else if ("C".equals(listen)) {
            this.calculate.refresh();
            this.input.setText("");
            this.temStr = "";
            this.barcketNum = 0;
            this.inSign();
        } else {
            JOptionPane.showMessageDialog(this, "error : unvaild input");
        }
        
        // 限制用户输入
        if (this.barcketNum < 0) {
            JOptionPane.showMessageDialog(this,"error : wrong number of barcket");
        }
        if(this.barcketNum == 0) {
            this.cal[3].setEnabled(false);
        }

        if (this.barcketNum > 0) {
            this.cal[18].setEnabled(false);
        }
    }


    public calculator(String uid) throws HeadlessException, SQLException, ClassNotFoundException {
        // 界面设置
        this.__init__();
        this.setNorth();
        this.setCenter();
        // 获取uid
        this.setUid(uid);
        this.setSouth();
        // 交互设置
        this.setListener();
        JOptionPane.showMessageDialog(this, "由于框架原因,本计算器打开时可能按钮显示不全,请最小化后打开");
        this.inSign();
        this.calculate.refresh();
    }

}

③Records类:链接数据库保存计算器运算记录

package com.auqa.version;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.swing.*;
import java.sql.*;

public class Records {
    Connection connection = null;
    Statement statement = null;

    public Records() throws SQLException, ClassNotFoundException {

        try {
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("123456");
            this.connection = mysqlDataSource.getConnection();
            this.statement = this.connection.createStatement();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "数据库连接失败", "提示", JOptionPane.WARNING_MESSAGE);
        }
    }

    public int excuteins(String uid,String records, String result) throws Exception {
        int temp = this.statement.executeUpdate("INSERT INTO record VALUE ('"+uid+"','"+records+"',"+result+")");
        return temp;
    }

}

3、Mian类:程序运行入口

import User.LoginDemo;

import javax.swing.*;

public class Main {
    public static void main(String[] args) {
        //界面渲染效果
        String lookAndFeel = "javax.swing.plaf.nimbus.NimbusLookAndFeel";
        try {
            UIManager.setLookAndFeel(lookAndFeel);
            LoginDemo log = new LoginDemo();
        } catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException | IllegalAccessException e) {
            JOptionPane.showMessageDialog(null, "系统异常", "警告", JOptionPane.WARNING_MESSAGE);
        }
    }
}