[实验目的]
1.掌握软件开发的基本流程
2.掌握常用的软件开发方式和工具。
[实验内容]
1. 设计一个包含登录界面的计算器软件,该软件可以实现第一次作业中的全部功能,同时可以保存用户的历史计算记录(保存数据最好使用数据库)。
一、计算器登录界面

图一、登录界面流程图
登录界面代码:Login.html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<link rel="shortcut icon" href="logins.png" type="image/x-icon" />
<title>计算器登录界面</title>
<script type="text/javascript" src="http://pv.sohu.com/cityjson?ie=utf-8"></script>
<script src="https://static.runoob.com/assets/jquery-validation-1.14.0/lib/jquery.js"></script>
<script src="https://static.runoob.com/assets/jquery-validation-1.14.0/dist/jquery.validate.min.js"></script>
<script src="https://static.runoob.com/assets/jquery-validation-1.14.0/dist/localization/messages_zh.js"></script>
<script type="text/javascript">
function randoms()
{
document.getElementById("id").value = "";
document.getElementById("password").value = "";
}
//参考链接:https://www.runoob.com/try/try.php?filename=jquery_validate_demo1
//添加检测机制 参考链接:https://blog.csdn.net/huangleijay/article/details/11569317
jQuery.validator.addMethod("mobile", function(value, element) {
var length = value.length;
var mobile = /^(((13)|1[5-9]{1})+\d{9})$/
return this.optional(element) || (length == 11 && mobile.test(value));
}, "手机号码格式错误");
// 字母和数字的验证
jQuery.validator.addMethod("chrnum", function(value, element) {
var chrnum = /^([a-zA-Z0-9]+)$/;
return this.optional(element) || (chrnum.test(value));
}, "只能输入数字和字母(字符A-Z, a-z, 0-9)");
//下面是表单拦截提示,可取消,否则无法跳转
/*
$.validator.setDefaults({
submitHandler: function() {
//alert("提交事件!");
}
});*/
$().ready(function() {
// 在键盘按下并释放及提交后验证提交表单
$("#loginform").validate({
rules: {
id: "required",//用户名
//密码是6位以上
password: {
required: true,
minlength:6,
maxlength:10,
chrnum: true
}
},
messages: {
id: "请输入您的账户名",
password: {
required: "请输入密码",
minlength: "请输入6~10位密码",
maxlength:"请输入6~10位密码"
}
}
});
});
</script>
<style>
.error{
color:red;
}
</style>
</head>
<body onload="randoms()">
<section>
<!-- 背景颜色 -->
<div class="color"></div>
<div class="color"></div>
<div class="color"></div>
<div class="box">
<!-- 背景圆 -->
<div class="circle" style="--x:0"></div>
<div class="circle" style="--x:1"></div>
<div class="circle" style="--x:2"></div>
<div class="circle" style="--x:3"></div>
<div class="circle" style="--x:4"></div>
<!-- 登录框 -->
<div class="container">
<div class="form">
<h2>登录</h2>
<form id = "loginform" action="login.php" method="post" name = "form1">
<div class="inputBox">
<input type="text" placeholder="账户" name="id" id="id">
</div>
<div class="inputBox">
<input type="password" placeholder="密码" name="password" id="password">
</div>
<div class="inputBox">
<input type="submit" value="登录" id="input1">
</div>
</form>
</div>
</div>
</div>
</section>
</body>
</html>
Css代码:Style.css代码
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
section {
position: relative;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
/* linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片 */
background: linear-gradient(to bottom, #f1f4f9, #dff1ff);
}
section .color {
position: absolute; /* 绝对定位 */
filter: blur(200px); /* 使用filter(滤镜) 属性,给图像设置高斯模糊*/
}
section .color:nth-child(1) {
top: -350px;
width: 600px;
height: 600px;
background: #ff359b;
}
section .color:nth-child(2) {
bottom: -150px;
left: 100px;
width: 500px;
height: 500px;
background: #fffd87;
}
section .color:nth-child(3) {
bottom: 50px;
right: 100px;
width: 500px;
height: 500px;
background: #00d2ff;
}
.box {
position: relative;
border-radius: 10px;
}
.box .circle {
position: absolute;
background: rgba(255, 255, 255, 0.1);
/* backdrop-filter属性为一个元素后面区域添加模糊效果 */
backdrop-filter: blur(5px);
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.5);
border-right: 1px solid rgba(255, 255, 255, 0.2);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
filter: hue-rotate(calc(var(--x) * 70deg));
animation: animate 10s linear infinite;
animation-delay: calc(var(--x) * -1s);
}
@keyframes animate {
0%, 100%{
transform: translateY(-50px);
}
50% {
transform: translateY(50px);
}
}
.box .circle:nth-child(1) {
top: -50px;
right: -60px;
width: 100px;
height: 100px;
}
.box .circle:nth-child(2) {
top: 150px;
left: -100px;
width: 120px;
height: 120px;
z-index: 2;
}
.box .circle:nth-child(3) {
bottom: 50px;
right: -60px;
width: 80px;
height: 80px;
z-index: 2;
}
.box .circle:nth-child(4) {
bottom: -80px;
left: 100px;
width: 60px;
height: 60px;
}
.box .circle:nth-child(5) {
top: -80px;
left: 140px;
width: 60px;
height: 60px;
}
.container {
position: relative;
width: 400px;
min-height: 400px;
background: rgba(255, 255, 255, 0.3);
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: blur(5px);
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.5);
border-right: 1px solid rgba(255, 255, 255, 0.2);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.form {
position: relative;
width: 100%;
height: 100%;
padding: 50px;
}
.checkip {
position: absolute;
left:0px;
bottom:-10px;
width: 100%;
height: 6%;
}
.form h2 {
position: relative;
color: #00aaff;
font-size: 24px;
font-weight: 600;
letter-spacing: 5px;
margin-bottom: 30px;
cursor: pointer;
}
.form h2::before {
content: "";
position: absolute;
left: 0;
bottom: -10px;
width: 0px;
height: 3px;
background: #fff;
transition: 0.5s;
}
.form h2:hover:before {
width: 53px;
}
.form .inputBox {
width: 100%;
margin-top: 20px;
}
.checkip .inputText {
width: 100%;
height:100%;
margin-top: 20px;
}
.form .inputBox input {
width: 100%;
padding: 10px 20px;
background: rgba(255, 255, 255, 0.2);
outline: none;
border: none;
border-radius: 30px;
border: 1px solid rgba(255, 255, 255, 0.5);
border-right: 1px solid rgba(255, 255, 255, 0.2);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
font-size: 16px;
letter-spacing: 1px;
color: #666;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.checkip .inputText input {
position: absolute;
width:55%;
right:20%;
bottom:50%;
background: rgba(255, 255, 255, 0);
outline: none;
border: 1px solid rgba(255, 255, 255, 0);
font-size: 14px;
letter-spacing: 1px;
color: #00aaff
}
.form .inputBox input::placeholder {
color: #666;
}
.form .inputBox input[type="submit"] {
background: #fff;
color: #666;
max-width: 100px;
margin-bottom: 20px;
font-weight: 600;
cursor: pointer;
}
.forget {
margin-top: 6px;
color: #236;
letter-spacing: 1px;
}
.goto {
position: absolute;
right: 3%;
bottom: 50%;
margin-top: 6px;
color: #236;
letter-spacing: 1px;
}
.goto a {
font-size:12px;
color: #aaaa00;
font-weight: 600;
text-decoration: none;
}
.forget a {
color: #236;
font-weight: 600;
text-decoration: none;
}
登录界面效果如下:


二、计算器功能的实现


图三、计算器保存历史记录
代码部分:
package 计算器;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
//Calculator类,继承JFrame框架,实现事件监听器接口
public class Calculator extends JFrame implements ActionListener {
private String[] KEYS = { "7", "8", "9", "AC", "4", "5", "6", "-", "1", "2", "3", "+", "0", "e", "pi", "/", "sqrt",
"%", "x*x", "*", "(", ")", ".", "=" };
private JButton keys[] = new JButton[KEYS.length];
private JTextArea resultText = new JTextArea("0.0");
private JTextArea History = new JTextArea();// 历史记录文本框初始值设为空
private JPanel jp1 = new JPanel();
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());
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 (label == "=")
{
resultText.setText(this.b);
History.setText(History.getText() + resultText.getText());
if (label == "=")// 调用计算方法,得出最终结果
{
String s[] = houzhui(this.b);
String result = Result(s);
this.b = result + "";
resultText.setText(this.b);
History.setText(History.getText() + "=" + resultText.getText() + "\n");
}
} else if (label == "AC")// 清空按钮,消除显示屏文本框前面所有的输入和结果
{
this.b = "";
resultText.setText("0");// 更新文本域的显示,显示初始值;
} else if (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 (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 if (label == "e" || label == "pi") {
if (label == "e") {
String m = String.valueOf(2.71828);// 将e的值以字符串的形式传给m
this.b = this.b + m;// 保留显示m之前输入的运算符或数字字符继续下一步运算
resultText.setText(this.b);
}
if (label == "pi") {
String m = String.valueOf(3.14159265);
this.b = this.b + m;
resultText.setText(this.b);
}
}
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++)// 遍历中缀表达式
{
if ("0123456789.".indexOf(str.charAt(i)) >= 0)
{
s = "";
for (; i < str.length() && "0123456789.".indexOf(str.charAt(i)) >= 0; i++) {
s = s + str.charAt(i);
}
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;// 循环结束
}
}
}
if ("*%/".indexOf(str.charAt(i)) >= 0)// 遇到高优先级运算符
{
if (top == -1) {// 若栈为空则直接入栈
top++;
opStack[top] = str.charAt(i);
} else {// 栈不为空,把栈中弹出的元素入队,直到栈顶元素优先级小于x或者栈为空
if ("*%/".indexOf(opStack[top]) >= 0) {
// 栈顶元素也为高优先级运算符
postQueue[j] = opStack[top] + "";// 栈顶元素出栈进入后缀表达式
j++;
opStack[top] = str.charAt(i);// 当前运算符入栈
} else if ("(".indexOf(opStack[top]) >= 0) {// 栈顶元素为左括号,当前运算符入栈
top++;
opStack[top] = str.charAt(i);
} else if ("+-".indexOf(str.charAt(i)) >= 0) {// 遇到低优先级运算符
postQueue[j] = opStack[top] + "";// 栈顶元素出栈进入后缀表达式
j++;
opStack[top] = str.charAt(i);// 当前元素入栈
}
}
} 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 if ("(".indexOf(opStack[top]) >= 0) {// 栈顶元素为左括号,当前运算符入栈
top++;
opStack[top] = str.charAt(i);
} else if ("+-".indexOf(str.charAt(i)) >= 0) {// 遇到低优先级运算符
postQueue[j] = opStack[top] + "";// 栈顶元素出栈进入后最表达式
j++;
opStack[top] = str.charAt(i);// 当前元素入栈
}
}
}
}
for (; 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)
{
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];// 返回最终结果
}
}
计算器功能实现效果如下图:


二、数据库连接代码
1、什么是JDBC
JDBC指java数据库连接(Java Database Connectivity),是一种标准的Java应用编程接口( JAVA API),JDBC本质上是Sun公司制定的一套接口(interface)!原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句来达到操控数据库的功能。


2、连接步骤.
(1)注册驱动
A.首先需要导入mysql驱动jar包
B.第一步:在当前项目下创建一个lib的目录:
C.第二步:把mysql的驱动jar拷贝到lib目录
D.第三步:把lib添加到项目中,作为当前项目的第三方库



3、加载并连接驱动
代码部分:
package com;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class TestMySql{
//驱动名称(包含了数据库的产品和数据库的版本号)
private static String driver = "com.mysql.jdbc.Driver";
//数据库的url
private static String url = "jdbc:mysql://127.0.0.1:3306sudent?characterEncoding=UTF-8";
//数据库用户名
private static String user = "root";
//数据库密码
private static String pass = "123456";
//使用jdbc进行添加操作
public static void select() throws Exception {
//加载mysql驱动
Class.forName(driver);
//获取数据库连接
Connection conn = DriverManager.getConnection(url,user,pass);
//编写sql语句
String sql = "insert into user(username,password) values('测试账号','测试密码')";
//创建Statement
Statement statement = conn.createStatement();
//执行sql语句
int count = statement.executeUpdate(sql);
System.out.println("执行sql成功,一共影响了"+count+"条数据");
//释放资源(建议先判断statement和conn是否为空再进行关闭)
if(statement != null){
statement.close();
}
if(conn != null){
conn.close();
}
}
//测试类的主方法
public static void main(String[] args) throws Exception {
select();
}
}
代码运行前数据库查询结果为:

代码运行结果:

代码运行后数据库查询结果为:
