第二次作业
一、实验目的
1.掌握软件开发的基本流程。
2.掌握软件设计和开发的基本工具。
3.理解集成软件开发环境在软件开发过程中的作用。
4.模拟计算器的功能,对数据进行加减乘除以及开方运算并可保存历史计算记录。
二、实验要求
1.完成计算器软件的UI设计、使用Visio设计计算器软件中所涉及的流程图。
2.选择合适的集成开发环境和工具完成计算器软件的开发和功能测试。
3.自己设计登录页面并和简易计算器连接并将数据保存在数据库中。
三、实验环境
1.操作系统:Windows11
2.开发测试工具:IDEA编写登录界面以及计算器相关代码,连接MySQL数据库存储计算记录。
3.流程图:visio
四、基本功能描述
一、相关功能
简易计算器包括基本的四则运算(加、减、乘、除)及开方运算并可存储历史计算数据功能。
二、JDBC相关介绍
JDBC核心接口与类:JDBC核心类库包含在java.sql包中。
接口:(1)Connection:特定数据库的连接(会话)。在连接上下文中执行SQL语句并返回结果。(2)PreparedStatement:表示预编译的 SQL 语句的对象。(3)Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。(4)ResultSet :表示数据库结果集的数据表,通常通过执行查询数据库的语句生成 。(5)CallableStatement :用于执行 SQL存储过程的接口 。
类:(1)DriverManager:负责管理JDBC驱动程序。使用JDBC驱动程序之前,必须先将驱动程序加载并注册后才可以使用,同时提供方法来建立与数据库的连接。(2)SQLException:有关数据库操作的异常

五、软件设计
1、登录界面设计
(1)流程图

(2)登录代码
package login;
import javax.swing.*;
import jisuanqi.Calculator;
import java.awt.*;
import java.awt.event.*;
public class Login extends JFrame {
private JTextField usernameField;
private JPasswordField passwordField;
private JButton loginButton;
private JButton registerButton;
public Login() {
// 设置窗口标题
setTitle("用户登录注册");
// 设置窗口大小
setSize(500,300);
// 设置窗口可调整大小
setResizable(true);
// 设置关闭窗口时的默认操作
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建用户名和密码输入框
usernameField = new JTextField(20);
passwordField = new JPasswordField(20);
// 创建登录和注册按钮
loginButton = new JButton("登录");
registerButton = new JButton("注册");
// 创建容器并设置布局管理器
Container container = getContentPane();
container.setLayout(new FlowLayout());
// 添加组件到容器中
container.setLayout(new GridLayout(3, 2)); // 设置网格布局,2行2列
container.add(new JLabel("用户名:"));
container.add(usernameField);
container.add(new JLabel("密码:"));
container.add(passwordField);
container.add(loginButton);
container.add(registerButton);
// 为登录按钮添加事件监听器
loginButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 进行登录逻辑处理
if (validateLogin()) {
// 登录成功后打开计算器界面
openCalculator();
} else {
JOptionPane.showMessageDialog(null, "用户名或密码错误", "登录失败", JOptionPane.ERROR_MESSAGE);
}
}
});
// 为注册按钮添加事件监听器
registerButton.addActionListener(new ActionListener() {
//@Override
public void actionPerformed(ActionEvent e) {
// 进行注册逻辑处理
if (validateRegister()) {
JOptionPane.showMessageDialog(null, "用户注册成功", "注册成功", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(null, "用户名已存在", "注册失败", JOptionPane.ERROR_MESSAGE);
}
}
});
}
private boolean validateLogin() {
// 实现登录验证逻辑
String username = usernameField.getText();
String password = new String(passwordField.getPassword());
// 假设正确的用户名是"l12345678",密码是“123456”
return "l12345678".equals(username) && "123456".equals(password);
}
private boolean validateRegister() {
// 实现注册验证逻辑
String username = usernameField.getText();
// 假设用户名不能重复,新用户注册时检查用户名是否已存在
// 这里简单地假设已存在一个用户"l12345678"
return !"l12345678".equals(username);
}
private void openCalculator() {
// 打开计算器界面
Calculator calculator = new Calculator();
calculator.setVisible(true);
}
public static void main(String[] args) {
// 在主线程中创建并显示登录注册界面
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Login frame = new Login();
frame.setVisible(true);
}
});
}
}
(3)运行完成后界面显示

用户名和密码都正确,点击登录打开计算器界面进行计算

注册

2、计算器设计
(1)计算器流程图

(2)代码
package jisuanqi;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Objects;
import javax.swing.*;
//Calculator类,继承JFrame框架,实现事件监听器接口
public class Calculator extends JFrame implements ActionListener {
private final String[] KEYS = { "sqrt","(", ")","AC","7", "8", "9", "÷" ,"4", "5", "6", "*", "1", "2", "3", "+", "0", "-",
"x*x", "=" };
private JButton keys[] = new JButton[KEYS.length];
private JTextArea resultText = new JTextArea("0.0");// 文本域组件TextArea可容纳多行文本;文本框内容初始值设为0.0
private JTextArea History = new JTextArea();// 历史记录文本框初始值设为空
private JPanel jp2=new JPanel();
private JScrollPane gdt1=new JScrollPane(resultText);//给输入显示屏文本域新建一个垂直滚动滑条
private JScrollPane gdt2=new JScrollPane(History);//给历史记录文本域新建一个垂直滚动滑条
private JScrollPane gdt3=new JScrollPane(History);//给历史记录文本域新建一个水平滚动滑条
private JLabel label = new JLabel("历史记录");
private String b = "";
// 构造方法
public Calculator() {
super("Caculator");//“超”关键字,表示调用父类的构造函数,
resultText.setBounds(20, 18, 255, 115);// 设置文本框大小
resultText.setAlignmentX(RIGHT_ALIGNMENT);// 文本框内容右对齐
resultText.setEditable(false);// 文本框不允许修改结果
History.setBounds(290, 40, 250,370);// 设置文本框大小
History.setAlignmentX(LEFT_ALIGNMENT);// 文本框内容右对齐
History.setEditable(false);// 文本框不允许修改结果
label.setBounds(300, 15, 100, 20);//设置标签位置及大小
jp2.setBounds(290,40,250,370);//设置面板窗口位置及大小
jp2.setLayout(new GridLayout());
JPanel jp1 = new JPanel();
jp1.setBounds(20,18,255,115);//设置面板窗口位置及大小
jp1.setLayout(new GridLayout());
resultText.setLineWrap(true);// 激活自动换行功能
resultText.setWrapStyleWord(true);// 激活断行不断字功能
resultText.setSelectedTextColor(Color.RED);
History.setLineWrap(true);//自动换行
History.setWrapStyleWord(true);
History.setSelectedTextColor(Color.blue);
gdt1.setViewportView(resultText);//使滚动条显示出来
gdt2.setViewportView(History);
gdt1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//设置让垂直滚动条一直显示
gdt2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//设置让垂直滚动条一直显示
gdt2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);//设置让水平滚动条一直显示
jp1.add(gdt1);//将滚动条添加入面板窗口中
jp2.add(gdt2);
this.add(jp1);//将面板添加到总窗体中
this.add(jp2);//将面板添加到总窗体中
this.setLayout(null);
this.add(label);// 新建“历史记录”标签
// 放置按钮
int x = 20, y = 150;
for (int i = 0; i < KEYS.length; i++)
{
keys[i] = new JButton();
keys[i].setText(KEYS[i]);
keys[i].setBounds(x, y, 60, 40);
if (x < 215) {
x += 65;
} else {
x = 20;
y += 45;
}
this.add(keys[i]);
}
for (int i = 0; i < KEYS.length; i++)// 每个按钮都注册事件监听器
{
keys[i].addActionListener(this);
}
this.setResizable(false);
this.setBounds(500, 200, 567, 480);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
// 事件处理
public void actionPerformed(ActionEvent e)
{
String label=e.getActionCommand();//获得事件源的标签
if(Objects.equals(label, "="))//
{
resultText.setText(this.b);
History.setText(History.getText()+resultText.getText());
if(label.equals("="))//调用计算方法,得出最终结果
{
String[] s =houzhui(this.b);
String result=Result(s);
this.b=result+"";
//更新文本框,当前结果在字符串b中,并未删除,下一次输入接着此结果以实现连续运算
resultText.setText(this.b);
History.setText(History.getText()+"="+resultText.getText()+"\n");
}
}
else if(Objects.equals(label, "AC"))//清空按钮,消除显示屏文本框前面所有的输入和结果
{
this.b="";
resultText.setText("0");//更新文本域的显示,显示初始值;
}
else if(Objects.equals(label, "sqrt"))
{
String n=kfys(this.b);
resultText.setText("sqrt"+"("+this.b+")"+"="+n);//使运算表达式显示在输入界面
History.setText(History.getText()+"sqrt"+"("+this.b+")"+"=");//获取输入界面的运算表达式并使其显示在历史记录文本框
this.b=n;
}
else if(Objects.equals(label, "x*x"))
{
String m=pfys(this.b);
resultText.setText(this.b+"^2"+"="+m);//使运算表达式显示在输入界面
History.setText(History.getText()+this.b+"^2"+"=");//获取输入界面的运算表达式并使其显示在历史记录文本框
this.b=m;
}
else
{
this.b=this.b+label;
resultText.setText(this.b);
}
}
//将中缀表达式转换为后缀表达式
private String[] houzhui(String str) {
String s = "";// 用于承接多位数的字符串
char[] opStack = new char[100];// 静态栈,对用户输入的操作符进行处理,用于存储运算符
String[] postQueue = new String[100];// 后缀表达式字符串数组,为了将多位数存储为独立的字符串
int top = -1, j = 0;// 静态指针top,控制变量j
for (int i = 0; i < str.length(); i++)// 遍历中缀表达式
// indexof函数,返回字串首次出现的位置;charAt函数返回index位置处的字符;
{
if ("0123456789.".indexOf(str.charAt(i)) >= 0) // 遇到数字字符的情况直接入队
{
s = "";// 作为承接字符,每次开始时都要清空
for (; i < str.length() && "0123456789.".indexOf(str.charAt(i)) >= 0; i++) {
s = s + str.charAt(i);
//比如,中缀表达式:234+4*2,我们扫描这个字符串的时候,s的作用相当于用来存储长度为3个字符的操作数:234
}
i--;
postQueue[j] = s;// 数字字符直接加入后缀表达式
j++;
}
else if ("(".indexOf(str.charAt(i)) >= 0) {// 遇到左括号
top++;
opStack[top] = str.charAt(i);// 左括号入栈
}
else if (")".indexOf(str.charAt(i)) >= 0) {// 遇到右括号
for (;;)// 栈顶元素循环出栈,直到遇到左括号为止
{
if (opStack[top] != '(') {// 栈顶元素不是左括号
postQueue[j] = opStack[top] + "";// 栈顶元素出栈
j++;
top--;
} else { // 找到栈顶元素是左括号
top--;// 删除栈顶左括号
break;// 循环结束
}
}
}
else if ("*÷+-".indexOf(str.charAt(i)) >= 0)// 遇到运算符
{
if (top == -1)
{// 若栈为空则直接入栈
top++;
opStack[top] = str.charAt(i);
}
else if ("*÷".indexOf(opStack[top]) >= 0)
{// 当栈顶元素为高优先级运算符时,让栈顶元素出栈进入后缀表达式后,当前运算符再入栈
postQueue[j] = opStack[top] + "";
j++;
opStack[top] = str.charAt(i);
}
else
{
top++;
opStack[top] = str.charAt(i);// 当前元素入栈
}
}
}
while (top != -1) {// 遍历结束后将栈中剩余元素依次出栈进入后缀表达式
postQueue[j] = opStack[top] + "";
j++;
top--;
}
return postQueue;
}
//开方运算方法
public String kfys(String str) {
String result = "";
double a = Double.parseDouble(str), b = 0;
b = Math.sqrt(a);
result = String.valueOf(b);//将运算结果转换为string类型并赋给string类型的变量result
return result;
}
//平方运算方法
public String pfys(String str) {
String result = "";
double a = Double.parseDouble(str), b = 0;
b = Math.pow(a, 2);
result = String.valueOf(b);
return result;
}
// 计算后缀表达式,并返回最终结果
public String Result(String[] str) {
String[] Result = new String[100];// 顺序存储的栈,数据类型为字符串
int Top = -1;// 静态指针Top
for (int i = 0; str[i] != null; i++) {
if ("+-*÷".indexOf(str[i]) < 0) { //遇到数字,直接入栈
Top++;
Result[Top] = str[i];
}
if ("+-*÷".indexOf(str[i]) >= 0)// 遇到运算符字符,将栈顶两个元素出栈计算并将结果返回栈顶
{
double x, y, n;
x = Double.parseDouble(Result[Top]);// 顺序出栈两个数字字符串,并转换为double类型
Top--;
y = Double.parseDouble(Result[Top]);
Top--;
if ("*".indexOf(str[i]) >= 0) {
n = y * x;
Top++;
Result[Top] = String.valueOf(n);// 将运算结果重新入栈
}
if ("÷".indexOf(str[i]) >= 0)
{
if (x == 0)// 被除数不允许为0
{
String s = "error!";
return s;
} else {
n = y / x;
Top++;
Result[Top] = String.valueOf(n);// 将运算结果重新入栈
}
}
if ("-".indexOf(str[i]) >= 0) {
n = y - x;
Top++;
Result[Top] = String.valueOf(n);// 将运算结果重新入栈
}
if ("+".indexOf(str[i]) >= 0) {
n = y + x;
Top++;
Result[Top] = String.valueOf(n);// 将运算结果重新入栈
}
}
}
return Result[Top];// 返回最终结果
}
// 主函数
public static void main(String[] args) {
Calculator a = new Calculator();
}
}
(3)功能测试
(1)加法;用户计算完后可点击AC键将计算框清零也可继续计算

(2)减法;用户计算完后可点击AC键将计算框清零也可继续计算

(3)乘法;用户计算完后可点击AC键将计算框清零也可继续计算

(4)除法用户计算完后可点击AC键将计算框清零也可继续计算

除法中除数不能为零,为零时报错

3、连接数据库将结果保存在数据库中
(1)代码
package com.jilu.domian;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class MySQLConnection {
public static void main(String[] args) {
// 数据库连接信息
String url = "jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8";
String user = "root";
String password = "123456";
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 建立数据库连接
Connection connection = DriverManager.getConnection(url, user, password);
// 创建Statement对象
Statement statement = connection.createStatement();
// 增加数据
String insertQuery = "INSERT INTO history (a, b) VALUES ('value1', 'value2')";
statement.executeUpdate(insertQuery);
// 删除数据
String deleteQuery = "DELETE FROM history WHERE a = 'value1'";
statement.executeUpdate(deleteQuery);
// 修改数据
String updateQuery = "UPDATE history SET b = 'newvalue' WHERE a = 'value1'";
statement.executeUpdate(updateQuery);
// 关闭连接
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
(2)结果:
建立表

连接数据库

保存数据


浙公网安备 33010602011771号