这个作业属于哪个课程 | 2301-计算机学院-软件工程社区-CSDN社区云 |
---|---|
这个作业要求在哪里 | 第二次作业--前后端交互计算器-CSDN社区 |
这个作业的目标 | 前后端分离基础计算器:实现基础计算和历史记录读取功能 前后端分离利率计算器:实现存款、贷款利息计算 两个计算器之间的切换 |
其他参考文献 |
1、Gitcode项目地址
前端:Heart1018/calculator-front-end (github.com)
后端:Heart1018/calculator-back-end (github.com)
2、PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
• Estimate | • 估计这个任务需要多少时间 | 10 | 20 |
Development | 开发 | 400 | 500 |
• Analysis | • 需求分析 (包括学习新技术) | 500 | 600 |
• Design Spec | • 生成设计文档 | 30 | 30 |
• Design Review | • 设计复审 | 40 | 50 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 40 |
• Design | • 具体设计 | 90 | 120 |
• Coding | • 具体编码 | 400 | 480 |
• Code Review | • 代码复审 | 30 | 40 |
• Test | • 测试(自我测试,修改代码,提交修改) | 100 | 150 |
Reporting | 报告 | 30 | 40 |
• Test Repor | • 测试报告 | 30 | 30 |
• Size Measurement | • 计算工作量 | 10 | 15 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 20 | 25 |
合计 | 1750 | 2170 |
3、成品展示
基础计算器
基础加减乘除运算
科学计算器
错误提醒
除数为0:
小数阶乘:
.
一个数中出现两个小数点:
获取历史记录
页面切换
利息计算器
计算存款利息
计算贷款利息
4、设计实现过程
1、前端部分:使用vue构建可视化界面,在前端实现基础计算器和利息计算器之间的切换;
在前端获取鼠标点击请求后,判断要进行的操作并将数据通过axios传给后端,在后端完成操作后获取后端返回的数据并进行后续操作;
2、后端部分:后端框架部分使用springboot,获取前端数据后将数据进行处理并存入数据库或从数据库中获取前端所需数据,并将数据返回前端。
5、代码说明
前端部分
HTML
进行页面模块的初始化
<template>
<div class="calculator" v-if=temp>
<div class="result" style="grid-area: result">{{result}}</div>
<button style="grid-area: ac" @click="Clear()">AC</button>
<button style="grid-area: add" @click="ClickOp('+')">+</button>
<button style="grid-area: sub" @click="ClickOp('-')">-</button>
<button style="grid-area: mul" @click="ClickOp('×')">×</button>
<button style="grid-area: div" @click="ClickOp('÷')">÷</button>
<button style="grid-area: equal" @click="ClikcEqual()">=</button>
<button style="grid-area: LN" @click="ClickOp('ln')">ln</button>
<button style="grid-area: SIN" @click="ClickOp('sin')">sin</button>
<button style="grid-area: COS" @click="ClickOp('cos')">cos</button>
<button style="grid-area: TAN" @click="ClickOp('tan')">tan</button>
<button style="grid-area: factorial" @click="ClickOp('!')">!</button>
<button style="grid-area: SQRT" @click="ClickOp('√')">sqrt</button>
<button style="grid-area: power" @click="ClickOp('^')">^</button>
<button style="grid-area: number-1" @click="ClickNum('1')">1</button>
<button style="grid-area: number-2" @click="ClickNum('2')">2</button>
<button style="grid-area: number-3" @click="ClickNum('3')">3</button>
<button style="grid-area: number-4" @click="ClickNum('4')">4</button>
<button style="grid-area: number-5" @click="ClickNum('5')">5</button>
<button style="grid-area: number-6" @click="ClickNum('6')">6</button>
<button style="grid-area: number-7" @click="ClickNum('7')">7</button>
<button style="grid-area: number-8" @click="ClickNum('8')">8</button>
<button style="grid-area: number-9" @click="ClickNum('9')">9</button>
<button style="grid-area: number-0" @click="ClickNum('0')">0</button>
<button style="grid-area: dot" @click="ClickPoint('.')">.</button>
</div>
<div class="select" >
<button class="select1" style="grid-area: select1" @click="ClikcSelect1()">基础计算器</button>
<button class="select2" style="grid-area: select2" @click="ClikcSelect2()">利率计算器</button>
</div>
<table class="history" v-if=temp>
<thead>
<tr>
<th>算式</th>
<th>结果</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in historydata">
<td>{{ item.resultString }}</td>
<td>{{ item.result }}</td>
</tr>
</tbody>
</table>
<button class="gethistory" @click="GetHistory()" v-if=temp>获取历史记录</button>
<div class="intersetcalculator" v-if=!temp>
<input type="text" name="time" style="grid-area: time" v-model="year">
<div class="settime" style="grid-area: settime" >时间(年)</div>
<input type="text" name="money" style="grid-area: money" v-model="money">
<div class="setmoney" style="grid-area: setmoney">金额</div>
<div class="restmoney" style="grid-area: restmoney">{{restmoney}}</div>
<button class="getrestmoney" style="grid-area: getrestmoney" @click="ClickRestMoney()">查询存款利息</button>
<div class="borrowmoney" style="grid-area: borrowmoney">{{borrowmoney}}</div>
<button class="getborrowmoney" style="grid-area: getborrowmoney" @click="ClickBorrowMoney()">查询贷款利息</button>
</div>
</template>
JS
进行前端各按键的功能实现
<script setup>
import { reactive, ref } from 'vue';
import axios from 'axios';
const result=ref("0");
const temp=ref(true);
const historydata=ref({});
const restmoney=ref();
const borrowmoney=ref();
const year=ref();
const money=ref();
const isOperator=false;//判断是否是第一个操作符
const isNum=false;//判断是否是第一个参与运算的数
const is_Point=false;//判断一个数字中是否出现两次小数点
const isFactorial=false;//判断是否进行阶乘运算
const restrate=0.0;
const borrowrate=0.0;
function ClickNum(number){
if(!this.isFactorial){
if(!this.isNum){
if(number!='0')
this.isNum=true;
result.value=number;
}
else{
result.value+=number;
}
}
else{
result.value='ERROR';
}
}
function ClickOp(operator){
if(!this.isOperator){
if(operator=='+'||operator=='-'||operator=='×'||operator=='÷'||operator=='^'){
result.value+=operator;
this.isNum=true;
}
else if(operator=='ln'||operator=='sin'||operator=='cos'||operator=='tan'||operator=='√'){
if(this.isNum){
result.value='ERROR';
}
else{
this.isNum=true;
result.value=operator;
}
}
else if(operator=='!'){
if(this.is_Point){
result.value='ERROR';
}
else{
result.value+=operator;
this.isFactorial=true;
}
}
this.isOperator=true;
this.is_Point=false;
}
else{
result.value='ERROR';
}
}
function Clear(){
this.isOperator=false;
this.isNum=false;
this.is_Point=false;
this.isFactorial=false;
result.value='0';
}
function ClickPoint(point){
if(!this.is_Point){
result.value+=point;
this.is_Point=true;
this.isNum=true;
}
else{
result.value='ERROR';
}
}
function ClikcEqual(){
axios.post("http://localhost:8081/claculator",{result:result.value
}).then(response=>{
result.value=response.data;
})
}
function ClikcSelect1(){
this.temp=true;
}
function ClikcSelect2(){
this.temp=false;
}
function GetHistory(){
axios.get("http://localhost:8081/history").then(response=>{
historydata.value=response.data;
console.log(historydata);
})
}
function ClickRestMoney(){
axios.post("http://localhost:8081/restclaculator",{result:year.value
}).then(response=>{
this.restrate=response.data;
restmoney.value=this.restrate*money.value*year.value;
})
}
function ClickBorrowMoney(){
axios.post("http://localhost:8081/borrowclaculator",{result:year.value
}).then(response=>{
this.borrowrate=response.data;
borrowmoney.value=this.borrowrate*money.value*year.value;
})
}
</script>
CSS
完成可视化界面的设计
<style>
body {
display: flex;
justify-content : center;
align-items: center;
min-height: 100vh;
}
.calculator {
--button-width: 80px;
--button-height: 80px;
display: grid;
grid-template-areas: "result result result result result result"
"number-1 number-2 number-3 add equal TAN"
"number-4 number-5 number-6 sub LN factorial"
"number-7 number-8 number-9 mul SIN SQRT"
"number-0 dot ac div COS power";
grid-template-columns: repeat(6, var(--button-width));
grid-template-rows: repeat(5, var(--button-height));
box-shadow: -8px -8px 16px -10px rgba(255,255,255,1),8px 8px 16px -10px rgba(0,0,0,.15);
padding: 24px;
border-radius: 20px;
position:absolute;
top: 150px;
left: 400px;
}
.calculator button {
margin: 8px;
padding: 0;
border: 0;
display: block;
outline: none;
border-radius: calc(var(--button-height)/2);
font-size: 24px;
font-weight: normal;
color: #999;
}
.calculator button:active{
box-shadow: -4px -4px 10px -8px rgba(255,255,255,1) inset,4px 4px 10px -8px rgba(0,0,0,.3) inset;
}
.result {
text-align: right;
line-height: var(--button-height);
font-size: 48px;
padding: 0 20px;
color: #666;
}
.select {
position:absolute;
top:150px;
left:100px;
display: grid;
grid-template-areas: "select1"
"select2";
grid-template-columns: repeat(1, var(--button-width));
grid-template-rows: repeat(2, var(--button-height));
}
.select1{
margin: 8px;
padding: 0;
border: 0;
outline: none;
line-height: var(--button-height);
font-size: 30px;
font-weight: normal;
padding: 0 20px;
color: #666;
}
.select2{
margin: 8px;
padding: 0;
border: 0;
outline: none;
line-height: var(--button-height);
font-size: 30px;
font-weight: normal;
padding: 0 20px;
color: #666;
}
.select button:active{
box-shadow: -4px -4px 10px -8px rgba(255,255,255,1) inset,4px 4px 10px -8px rgba(0,0,0,.3) inset;
}
.history{
position:absolute;
top:150px;
left:1100px;
}
.history th{
margin: 8px;
padding: 0;
border: 0;
outline: none;
line-height: var(--button-height);
font-size: 30px;
font-weight: normal;
padding: 0 20px;
color: #666;
}
.history td{
margin: 8px;
padding: 0;
border: 0;
outline: none;
line-height: var(--button-height);
font-size: 30px;
font-weight: normal;
padding: 0 20px;
color: #666;
}
.gethistory{
position:absolute;
top:100px;
left:1100px;
margin: 8px;
padding: 0;
border: 0;
outline: none;
line-height: var(--button-height);
font-size: 30px;
font-weight: normal;
padding: 0 20px;
color: #666;
}
.gethistory:active{
box-shadow: -4px -4px 10px -8px rgba(255,255,255,1) inset,4px 4px 10px -8px rgba(0,0,0,.3) inset;
}
.intersetcalculator{
display: grid;
grid-template-areas: "time settime"
"money setmoney"
"restmoney getrestmoney"
"borrowmoney getborrowmoney";
grid-template-columns: repeat(2, var(--button-width));
grid-template-rows: repeat(4, var(--button-height));
position:absolute;
top: 160px;
left: 600px;
}
.time{
text-align: right;
line-height: var(--button-height);
font-size: 72px;
padding: 0 20px;
color: #666;
}
.settime{
text-align: right;
line-height: var(--button-height);
font-size: 24px;
padding: 0 20px;
color: #666;
}
.money{
text-align: right;
line-height: var(--button-height);
font-size: 72px;
padding: 0 20px;
color: #666;
}
.setmoney{
text-align: right;
line-height: var(--button-height);
font-size: 24px;
padding: 0 20px;
color: #666;
}
.restmoney{
text-align: right;
line-height: var(--button-height);
font-size: 24px;
padding: 0 20px;
color: #666;
}
.borrowmoney{
text-align: right;
line-height: var(--button-height);
font-size: 24px;
padding: 0 20px;
color: #666;
}
.getrestmoney{
text-align: right;
line-height: var(--button-height);
font-size: 24px;
padding: 0 20px;
color: #666;
}
.getborrowmoney{
text-align: right;
line-height: var(--button-height);
font-size: 24px;
padding: 0 20px;
color: #666;
}
</style>
后端部分
函数claculate通过接受前端通过/claculator传来的POST请求,获取前端传来的算式并进行计算,计算完成后将算式及其结果一起存入绑定的数据库的result表中
@PostMapping("/claculator")
public String claculate(@RequestBody Map<String,Object> map){
String result=map.get("result").toString();
String resultstr=map.get("result").toString();
String op="";
if(result.indexOf("+")!=-1){
Double num1=Double.valueOf(result.substring(0,result.indexOf("+")));
Double num2=Double.valueOf(result.substring(result.indexOf("+")+1));
Double res=num1+num2;
result=Double.toString(res);
}
else if(result.indexOf("-")!=-1){
Double num1=Double.valueOf(result.substring(0,result.indexOf("-")));
Double num2=Double.valueOf(result.substring(result.indexOf("-")+1));
Double res=num1-num2;
result=Double.toString(res);
}
else if(result.indexOf("×")!=-1){
Double num1=Double.valueOf(result.substring(0,result.indexOf("×")));
Double num2=Double.valueOf(result.substring(result.indexOf("×")+1));
Double res=num1*num2;
result=Double.toString(res);
}
else if(result.indexOf("÷")!=-1){
Double num1=Double.valueOf(result.substring(0,result.indexOf("÷")));
Double num2=Double.valueOf(result.substring(result.indexOf("÷")+1));
if(num2==0.0){
result="ERROR";
}
else {
Double res = num1 * num2;
result = Double.toString(res);
}
}
else if(result.indexOf("ln")!=-1){
Double num1=Double.valueOf(result.replace("ln",""));
Double res=Math.log(num1);
result=Double.toString(res);
}
else if(result.indexOf("sin")!=-1){
Double num1=Double.valueOf(result.replace("sin",""));
Double res=Math.sin(num1);
result=Double.toString(res);
}
else if(result.indexOf("cos")!=-1){
Double num1=Double.valueOf(result.replace("cos",""));
Double res=Math.cos(num1);
result=Double.toString(res);
}
else if(result.indexOf("tan")!=-1){
Double num1=Double.valueOf(result.replace("tan",""));
Double res=Math.tan(num1);
result=Double.toString(res);
}
else if(result.indexOf("!")!=-1){
Integer num1=Integer.valueOf(result.replace("!",""));
Double res=1.0;
for(Integer i=num1;i>0;i--){
res*=i;
}
result=Double.toString(res);
}
else if(result.indexOf("√")!=-1){
Double num1=Double.valueOf(result.replace("√",""));
Double res=Math.sqrt(num1);
result=Double.toString(res);
}
else if(result.indexOf("^")!=-1){
Double num1=Double.valueOf(result.substring(0,result.indexOf("^")));
Double num2=Double.valueOf(result.substring(result.indexOf("^")+1));
Double res=Math.pow(num1,num2);
result=Double.toString(res);
if(num1==0)
result="0";
}
resultService.save(new Result(resultstr,result));//将数据存入数据库
return result;
}
获取前端“获取历史记录”的请求,向数据库的result表发送请求,获得result表中的记录,并通过json形式送回前端,前端再通过v-for在<table>组件中将历史记录显示出来
@GetMapping("/history")
public List<Result> test(){
QueryWrapper<Result> resultQueryWrapper=new QueryWrapper<>();//QueryWrapper:构造器
return resultService.list();
}
后端从前端获取存款时间,将时间与后台数据库中保存的利率表中进行比较,向前端返回该时间对应的利率,前端获取利率后进行利息计算并将结果在web页面上进行输出。下面只列出存款利率的获取,贷款利率获取部分在GitHub的后端部分中有:
@PostMapping("/restclaculator")
public String restclaculator(@RequestBody Map<String,Object> map){
QueryWrapper<Rest> restQueryWrapper=new QueryWrapper<>();
double year= Double.valueOf((String) map.get("result").toString());
Double temp=0.0;
if(0.0<year&&year<=0.5){
restQueryWrapper.eq("rest_year",0.5);
Rest rest = restService.getOne(restQueryWrapper);
temp=rest.getRestRate();
}
else if(0.5<year&&year<=1){
restQueryWrapper.eq("rest_year",1);
Rest rest = restService.getOne(restQueryWrapper);
temp=rest.getRestRate();
}
else if(1<year&&year<=2){
restQueryWrapper.eq("rest_year",2);
Rest rest = restService.getOne(restQueryWrapper);
temp=rest.getRestRate();
}
else if(2<year&&year<=3){
restQueryWrapper.eq("rest_year",3);
Rest rest = restService.getOne(restQueryWrapper);
temp=rest.getRestRate();
}
else if(3<year){
restQueryWrapper.eq("rest_year",4);
Rest rest = restService.getOne(restQueryWrapper);
temp=rest.getRestRate();
}
String result=Double.toString(temp);
return result;
}
6、心路历程和收获
之前从来没有接触过前端和后端框架相关的任何知识,所以刚看到作业的时候还是比较害怕的,但还是第一时间投入到了相关知识的学习。这十天左右的课余时间几乎全扑在了相关知识的学习上,学习的过程中遇到了很多的困难和困惑,也走了不少的弯路,但最终还是跌跌撞撞地完成了这一次作业。虽然还有很多的缺陷和不足,例如还不能进行算式的复杂运算和可视化界面做得实在不够美观,但我对这次作业自己的完成情况还是比较满意的。
这次作业让我学习了使用Vue进行前端的构建,除Vue的基础知识外还掌握了v-if、v-for的使用以及通过axios向后端发送请求,进行前后端的连接互动。后端部分让我初步熟悉了spring boot框架的搭建和如何与前端建立连接和接受、传送数据,学习了如何绑定数据库,巩固了我作为初学者对于JAVA的使用,让我对JAVA的使用更加得心应手。同时对代码的书写规范有了更深的理解,例如如何更好地对类进行封装、驼峰命名的使用等基础的代码书写规范。
特别感谢102101216庄泽、102101227陈艺、102101232范远生和102101244魏知乐在百忙之中抽出时间指导我应使用和学习哪些部分的知识并为我答疑解惑,让我在学习前后端知识的过程中少走了很多的弯路!