前后端分离实现计算器

这个作业属于哪个课程<https://bbs.csdn.net/forums/ssynkqtd-05?typeId=5171424>
这个作业要求在哪里<https://bbs.csdn.net/topics/617377308>
这个作业的目标前后端分离,实现基础计算器和利率计算器
其他参考文献

目录

一、git仓库链接和代码规范链接

二、PSP表格

三、成品展示

四、设计实现过程

五、代码说明

六、心路历程和收获


一、git仓库链接和代码规范链接


102101101杨婧怡 / 前端 · GitCode

102101101杨婧怡 / 后端 · GitCode

https://www.cnblogs.com/LyndonMario/p/8149876.html

二、PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3040
• Estimate• 估计这个任务需要多少时间3040
Development开发13601760
• Analysis• 需求分析 (包括学习新技术)800850
• Design Spec• 生成设计文档4050
• Design Review• 设计复审4050
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)2020
• Design• 具体设计80100
• Coding• 具体编码400500
• Code Review• 代码复审6060
• Test• 测试(自我测试,修改代码,提交修改)100130
Reporting报告105110
• Test Repor• 测试报告6060
• Size Measurement• 计算工作量1520
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划3030
合计14951910

三、成品展示

1.基础计算器

  • 功能1:加减乘除、取余、括号运算

  • 功能2:清零回退
    • 实现字符串输入的清零和回退功能
  • 功能3:错误提示

异常抛出

  • 功能4:读取历史记录
    • 能用ans按钮返回上一个计算结果,并且查看历史记录读取最后一个字符串式子和对应的计算结果

2.利率计算器

利率计算器做的有问题(显示利率的小数点错了,还有目前只能算最上面的那个选项......可惜这周时间来不及改)

  • 存款利率

  • 贷款利率

四、设计实现过程

1.前端使用vue,展示页面并将运算结果返回到后端,查询历史记录时从后端读取。

若计算存贷款利率则从后端获取利率。

2.数据库中新建存放历史记录、存贷款利率的表。

3.后端使用了springboot和mybatis,将运算结果存到历史记录,接收到前端查询请求时从数据库中查询。

五、代码说明

前端的计算器页面

<template>
  <div class="computeds-container">
    <input class="input" :value="value" disabled>
    <div class="click-btns">
      <button v-for="(item, i) in btnArr" :key="i" @click="clickBtnFn(i, item)" class="btn"
        :class="{ 'btn0': i === 28 }">{{ item }}</button>
    </div>
    <el-table :data="tableData" style="width: 100%">
      <el-table-column prop="history" label="历史记录" width="200">
      </el-table-column>
    </el-table>
  </div>
  <!--展示历史记录
  -->
</template>
<script>
// import axios from 'axios'

import requests from "../utils/request";

export default {
  name: 'ComputedS',
  data() {
    return {
      btnArr: [
        '(', ')', '%', '7', '8', '9', '/',
        'AC', 'sin', 'cos', '4', '5', '6', '*',
        'Back', 'tan', 'lg', 1, '2', '3', '-',
        'Ans', '^', '√', '.', '0', '=', '+',
      ],
      value: '',
      //historyShow: false

      tableData: [{ history: '' }]
    }
  },
  methods: {
    clickBtnFn(index, item) {
      this.value = this.value + ''
      //if (this.value === '') return
      //if (item === 'Ans') {//历史记录
      //  this.historyShow = !this.historyShow
      //}
      if (item === 'AC') {
        this.value = ''
      } else if (item === 'Back') {
        this.value = this.value.slice(0, this.value.length - 1)
      }
      else if (item === '=') {
        // this.value += item
        const exp = this.value;
        requests.get('/api/calculator?exp=' + exp).then(res => {
          console.log(res)
          if (res.data.status == 500) {
            this.$message({
              message: res.data.message,
              type: 'error'
            });
          }
          this.value = res.data

        })

      } else if (item == 'Ans') {
        requests.get('/api/history').then(res => {
          console.log(res.data)
          if (res.status == 200) {
            this.tableData = res.data.map((ele) => {
              return {
                history: ele.expression + ele.result
              }
            })

          }
        })
      }
      else {
        this.value += item
      }

    }
  }
}
</script>

<style lang="less" scoped>
.computeds-container {
  max-width: 550px;
  padding: 0 20px;
  background-color: #fafafa;
  border-radius: 20px;
  box-sizing: border-box;


  .input {
    width: 100%;
    height: 40px;
    padding: 0 20px;
    margin-bottom: 10px;
    border: 1px solid #b3d7dd;
    border-radius: 20px;
    text-align: right;
    font-size: 20px;
    line-height: 42px;
    box-sizing: border-box;
  }

  .click-btns {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;

    .btn {
      //width=
      flex: 10%;
      padding: 12px 0px;
      margin: 10px;
      background-color: #b3d7dd;
      border: 0;
      border-radius: 18px;
      box-shadow: 7px 7px 7px #aaa;
      font-size: 20px;
      cursor: pointer;
    }

    .btn0 {
      flex: 40%;
    }
  }
}
</style>

前端的利率计算器页面

<template>
  <div>
    <div>
      <span>利率计算器</span>
    </div>

    <el-row :gutter="20">
      <el-col :span="6">
        <el-input placeholder="请输入内容" v-model="inputRate" clearable>
        </el-input>
      </el-col>
      <!-- 利率类型展示 -->
      <el-col :span="6">
        <el-select v-model="value" clearable @change="getDuration()" placeholder="请选择利率类型">
          <el-option v-for="item in rateOptions" :key="item.id" :label="item.rateType" :value=item.rateType>
          </el-option>
        </el-select>
      </el-col>
      <!-- 周期利率下拉展示 -->
      <el-col :span="6">
        <el-select v-model="durationValue" clearable :disabled="selectDisabled" placeholder="请选择利率周期">
          <el-option v-for="item in durationOptions" :key="item.id" :label="item.durationRate" :value="item.id">
          </el-option>
        </el-select>
      </el-col>
      <el-input v-model="result" disabled placeholder="利率结果"></el-input>
    </el-row>



    <el-button type="primary" plain @click="calculator()">计算利率</el-button>

  </div>
</template>



<script>

import requests from "../utils/request";

export default {
  created() {
    requests.get('/api/rateType').then(res => {
      this.rateOptions = res.data
    })
  },
  data() {
    return {
      inputRate: '',
      rateOptions: [],
      value: '',
      selectDisabled: true,
      durationValue: '',
      durationOptions: [{
        id: 0,
        durationRate: '全部',
        duration: 0
      }],
      result: ''
    }
  },
  methods: {
    alertMessage() {
      if (this.value === '') {
        this.$message({
          message: '计算利率类型不能为空',
          type: 'error'
        });
      } else if (this.inputRate < 0) {
        this.$message({
          message: this.value + '不能为负数',
          type: 'error'
        });
      } else if (this.inputRate === '') {
        this.$message({
          message: '利率值不能为空',
          type: 'error'
        });
      }
    },
    getDuration() {
      if (this.value === '存款利率') {

        requests.get("/api/queryDeposit").then(res => {
          this.durationOptions = res.data.map((ele) => {
            var date = '年';
            if (ele.duration == 0.3 || ele.duration == 0.6) {
              ele.duration = ele.duration * 10;
              date = '月'
            }

            return {
              durationRate: ele.isDemand ? '活期存款' + ele.duration + date + " -" + (parseFloat(ele.rate) * 10).toFixed(2) + "%" : '定期存款' + ele.duration + date + " -" + (parseFloat(ele.rate) * 10).toFixed(2) + "%",
              id: ele.id,
              duration: ele.duration
            }
          })
        })
        this.selectDisabled = false;


      } else if (this.value === '贷款利率') {

        requests.get("/api/queryLoan").then(res => {
          this.durationOptions = res.data.map((ele) => {

            var date = '年';
            if (ele.duration == 0.6) {
              ele.duration = ele.duration * 10;
              date = '个月'
            } else if (ele.duration > 1 && ele.duration < 3) {
              ele.duration = '1至3'
            } else if (ele.duration > 3 && ele.duration < 5) {
              ele.duration = '3至5'
            }
            return {
              durationRate: ele.duration + date + " -" + (parseFloat(ele.rate) * 10).toFixed(2) + "%",
              id: ele.id,
              duration: ele.duration
            }
          })
        })
        this.selectDisabled = false;
      }
    },
    calculator() {
      // 类型和输入值校验
      this.alertMessage();
      if (this.value === '存款利率') {
        let id = this.durationOptions[0].id;
        let money = this.inputRate;
        requests.get('/api/deposit?money=' + money + '&duration=' + id).then(res => {
          this.result = res.data

        })

      } else if (this.value === '贷款利率') {

        let id = this.durationOptions[0].id;
        let money = this.inputRate;
        requests.get('/api/loan?money=' + money + '&duration=' + id).then(res => {
          this.result = res.data
        })

      }
    }
  }
}
</script>
<style lang="less" scoped>
.el-row {
  margin-bottom: 20px;

  &:last-child {
    margin-bottom: 0;
  }
}

.el-col {
  border-radius: 4px;
}

.bg-purple-dark {
  background: #99a9bf;
}

.bg-purple {
  background: #d3dce6;
}

.bg-purple-light {
  background: #e5e9f2;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}

.row-bg {
  padding: 10px 0;
  background-color: #f9fafc;
}
</style>

后端主要代码

package com.calculator.controller;


import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.calculator.entity.Calculator;
import com.calculator.entity.DepositRate;
import com.calculator.entity.LoanRate;
import com.calculator.service.CalculatorService;
import com.calculator.service.DepositRateService;
import com.calculator.service.LoanRateService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;


@RestController
@Slf4j
@CrossOrigin
public class CalculatorController {

    @Resource
    private  CalculatorService calculatorService;

    @Resource
    private DepositRateService depositRateService;

    @Resource
    private LoanRateService loanRateService;

    /**
     * 执行表达式
     *
     * @param exp 表达式
     * @return 计算结果
     */
    @GetMapping("/calculator")
    public  double calculate(String exp) {
        exp = exp.replaceAll(" ","+");
        return calculatorService.execute(exp);
    }


    /**
     * 查看记录
     *
     * @return 历史记录
     */
    @GetMapping("/history")
    public List<Calculator> history() {
        return calculatorService.list(Wrappers.<Calculator>lambdaQuery()
                .orderByDesc(Calculator::getCreateTime).last("limit 10"));
    }


    /**
     * 计算存款利息
     * @param money 存款金额
     * @param duration 存款期限
     *
     * @return  利息
     */
    @GetMapping("/deposit")
    public BigDecimal depositInterest(String money, Integer duration){
       if(StringUtils.isBlank(money)){
           throw  new RuntimeException("金额不能为空");
       }
         if(null == duration){
              throw  new RuntimeException("不能为空");
         }

        DepositRate depositRate= depositRateService.getOne(Wrappers.<DepositRate>lambdaQuery()
                .eq(DepositRate::getId, duration));
       return  NumberUtil.mul(new BigDecimal(money), new BigDecimal(depositRate.getRate()));
    }

    /**
     * 计算贷款利息
     * @param money 存款金额
     * @param duration 存款期限
     *
     * @return  利息
     */
    @GetMapping("/loan")
    public BigDecimal loanInterest(String money, Integer duration){
        if(StringUtils.isBlank(money)){
            throw  new RuntimeException("金额不能为空");
        }
        if(null == duration){
            throw  new RuntimeException("不能为空");
        }

        LoanRate loanRate= loanRateService.getOne(Wrappers.<LoanRate>lambdaQuery()
                .eq(LoanRate::getId, duration));
        return  NumberUtil.mul(new BigDecimal(money), new BigDecimal(loanRate.getRate()));
    }

    @GetMapping("/rateType")
    public List<RateTypeDTO> getRateType(){
        List<RateTypeDTO> rateTypeDTOList = new ArrayList<>();
        RateTypeDTO depositRateDTO = new RateTypeDTO();
        depositRateDTO.setId(1L);
        depositRateDTO.setRateType("存款利率");
        RateTypeDTO loanRateDTO = new RateTypeDTO();
        loanRateDTO.setId(2L);
        loanRateDTO.setRateType("贷款利率");
        rateTypeDTOList.add(depositRateDTO);
        rateTypeDTOList.add(loanRateDTO);
        return rateTypeDTOList;
    }


    /**
     * 获取存款周期利息

     * @return  利息
     */
    @GetMapping("/queryDeposit")
    public List<DepositRate> queryDeposit(){

        return  depositRateService.list();
    }

    /**
     * 获取贷款利息

     * @return  利息
     */
    @GetMapping("/queryLoan")
    public List<LoanRate> queryLoan(){

        return loanRateService.list();
    }


    @Data
    public static class RateTypeDTO{
        private Long id;
        private String rateType;
    }
}
package com.calculator.util;

import java.util.Stack;

public class CalculatorUtil {
    private Stack<Character> operators; // 运算符栈
    private Stack<Double> operands; // 操作数栈

    public CalculatorUtil() {
        operators = new Stack<>();
        operands = new Stack<>();
    }

    public double evaluateExpression(String expression) throws IllegalArgumentException {
        for (int i = 0; i < expression.length(); i++) {
            char ch = expression.charAt(i);

            if (ch == ' ') {
                continue; // 忽略空格
            } else if (Character.isDigit(ch) || ch == '.') {
                StringBuilder sb = new StringBuilder();
                sb.append(ch);
                while (i + 1 < expression.length() && (Character.isDigit(expression.charAt(i + 1)) || expression.charAt(i + 1) == '.')) {
                    sb.append(expression.charAt(++i));
                }
                operands.push(Double.parseDouble(sb.toString()));
            } else if (ch == '(') {
                operators.push(ch);
            } else if (ch == ')') {
                while (!operators.isEmpty() && operators.peek() != '(') {
                    evaluateOperation();
                }
                if (!operators.isEmpty() && operators.peek() == '(') {
                    operators.pop();
                } else {
                    throw new IllegalArgumentException("括号不匹配");
                }
            } else if (isOperator(ch)) {
                while (!operators.isEmpty() && getPriority(operators.peek()) >= getPriority(ch)) {
                    evaluateOperation();
                }
                operators.push(ch);
            } else {
                throw new IllegalArgumentException("非法输入");
            }
        }

        while (!operators.isEmpty()) {
            evaluateOperation();
        }

        return operands.pop();
    }

    private boolean isOperator(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%';
    }

    private int getPriority(char operator) {
        switch (operator) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
            case '%':
                return 2;
            default:
                return -1;
        }
    }

    private void evaluateOperation() throws IllegalArgumentException {
        char operator = operators.pop();

        if (operands.isEmpty()) {
            throw new IllegalArgumentException("非法输入");
        }

        double operand2 = operands.pop();
        double operand1 = operands.isEmpty() ? 0 : operands.pop();

        switch (operator) {
            case '+':
                operands.push(operand1 + operand2);
                break;
            case '-':
                operands.push(operand1 - operand2);
                break;
            case '*':
                operands.push(operand1 * operand2);
                break;
            case '/':
                if (operand2 == 0) {
                    throw new IllegalArgumentException("除数不能为0");
                }
                operands.push(operand1 / operand2);
                break;
            case '%':
                operands.push(operand1 % operand2);
                break;
        }
    }
}

六、心路历程和收获

        在本次制作计算器的过程中,的确收获了很多,学习到了很多vue、springboot、mysql的相关知识,过程挺坎坷的,最后bug没改完,作业是踩点交的,博客是踩点写的,很狼狈,写的很潦草,希望以后能避免这种情况的发生。这里也必须说一句,很感谢指点我的同学。虽然还有很多不足之处(没有做计算器的三角函数运算,利率计算器有很多问题等等),但是最后看见计算器能跑起来还是挺高兴的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值