Assignment 2: Back-end Separation Calculator Programming

cnskdncw 2023-10-22 01:26:15

https://github.com/QIU225/832101107_calculator_frontend.git

https://github.com/QIU225/832101107_calculator_backend.git

Course for This AssignmentSoftware Engineering
Assignment Requirementshttps://bbs.csdn.net/topics/617378696
Objectives of This AssignmentImplement the basic functions and extension functions of the calculator, and store the results in the back-end database, use the ans button to return the previous calculation results and view the history to read the most recent ten string formula and the corresponding calculation results.
Other ReferencesSpringboot+Mybatis连接mysql数据库_springboot使用mysql与mybatis数据库交互-CSDN博客

CATALOGUE

1. PSP Form

2. Presentation of the Finished Product

Front-end Page Presentation

Back-end Functionality Implementation

3. Design and Implementation Process

(1) Design phase

(2) Implementation stage

(3) Functional structure diagram

4. Code Explanation

Front-end

Back-end

5. Personal Journey and Learnings


1. PSP Form

Personal Software Process StagesEstimated Time(minutes)Actual Time(minutes)
Planning3030
Estimate3030
Development430695
Analysis3030
Design Spec3030
Design Review3035
Coding Standard2020
Design6080
Coding180360
Code Review2040
Test60100
Reporting120120
Test Repor4040
Size Measurement4040
Postmortem & Process Improvement Plan4040
Sum580845

 

2. Presentation of the Finished Product

Front-end Page Presentation

Back-end Functionality Implementation

  • Feature 1: Four Arithmetic Operations and Remainder

  • Feature 2: Calculate radical sign, trigonometric function, log, scientific notation

  • Feature 3: Implement bracket computation

  • Feature 4: Reading History Record

3. Design and Implementation Process

(1) Design phase

  • User interface design: In the design phase, I first considered the user interface of the calculator. I made sure the interface was user-friendly so that users could easily enter numbers and operators and see the results of calculations clearly.
  • Functional planning: I planned the functions of the calculator, including basic mathematical operations such as addition, subtraction, multiplication, and division. In addition, you also considered implementing more advanced features such as brackets, percentages, etc., to provide more comprehensive computing power.

(2) Implementation stage

  • Front-end development: I use wechat mini program framework for front-end development. This includes using WXML and WXSS to build user interfaces, and JavaScript to handle user interactions. I wrote event handlers to capture the user's input and perform the corresponding calculations based on the user's actions.
  • Back-end development: For back-end development, I use the Spring Boot framework. Spring Boot makes it relatively easy to create and manage RESTful API interfaces. I designed the API interface to receive requests from the front end. These interface handles process the data computed by the front-end and return the processing state to the front-end.
  • Database integration: To persist the data, I integrated the MySQL database and used MyBatis to handle the database interaction. I created entity classes to map database tables, and wrote and wrote SQL statements to perform the creation and read operations.

(3) Functional structure diagram

 

4. Code Explanation

Front-end

(1) In the wxss file, I updated the style layout to make the top two rows of buttons different from the rest of the buttons, and I changed the color of the calculator to make it more aesthetically pleasing. Here is the code for the major cuts.

/* 顶部两行按钮的样式 */
.buttons > view:nth-child(1),
.buttons > view:nth-child(2) {
  display: flex;
  font-size: 45rpx;
  background-color: rgb(255, 247, 247);
  justify-content: center; 
}

.buttons > view:nth-child(1) > view,
.buttons > view:nth-child(2) > view {
  flex: 1;
  text-align: center;
  width: 300rpx; 
  height: 100rpx;
  line-height: 100rpx; 
  border: none;
  background-color: rgb(245, 227, 227);
  box-shadow: 5px 5px 10px rgba(83, 5, 5, 0.2);
  transition: background-color 0.3s, transform 0.2s;
  margin: 12px;
  border-radius: 20%;
}

/* 其余按钮的样式 */
.buttons > view:not(:nth-child(1)):not(:nth-child(2)) > view {
  flex: 1;
  text-align: center;
  width: 80rpx;
  height: 120rpx;
  line-height: 120rpx; 
  border: none;
  background-color: rgb(247, 207, 207);
  box-shadow: 5px 5px 10px rgba(83, 5, 5, 0.2);
  transition: background-color 0.3s, transform 0.2s;
  margin: 10px;
  border-radius: 75%; 
}

(2) In the wxml file, I added the top two lines of buttons to make the calculator more functional.

    <view>
      <view bindtap="op" data-op="sci">sci</view>
      <view bindtap="op" data-op="√">√</view>
      <view bindtap="op" data-op="^">^</view>
      <view bindtap="op" data-op="(">(</view>
      <view bindtap="op" data-op=")">)</view>
    </view>

    <view> 
      <view bindtap="op" data-op="log">lg</view>
      <view bindtap="op" data-op="ln">ln</view>
      <view bindtap="op" data-op="sin">sin</view>
      <view bindtap="op" data-op="cos">cos</view>
      <view bindtap="op" data-op="tan">tan</view>
    </view>

(3) In the  js file, on the basis of the first implementation of basic calculator functions, I added trigonometric functions, logarithms, scientific counting methods and other expanded functions, as well as the function of querying history records.

Page({
  data: {
    result: '0',
    history: [],
    valiBackOfArray: [
      '+',
      '-',
      '×',
      '÷',
      '.',
      '√',
      '^',
      'log',
      'sci',
      'cos',
      'sin',
      'tan',
      'ln',
      'sci',
      '%',
      '(',
      ')',
    ],
    completeCalculate: false,
    openedParentheses: 0,
    hadleFlag:false,
    ansIndex:0
  },

  calculate: function (str) {
    const precedence = {
      '+': 1,
      '-': 1,
      '×': 2,
      '÷': 2,
      '%': 2,
      '^': 3,
      '√': 4,
      log: 4,
      sin: 4,
      cos: 4,
      tan: 4,
      ln:4,
      sci:4
    }

    const operators = []
    const operands = []
    const tokens = str.split(/([+\-×÷^()√%])/)
    console.log(tokens);
    tokens.forEach((token) => {
      if (token != '') {
        if (
          token in precedence ||
          token === '√' ||
          token === 'log' ||
          token === 'sin' ||
          token === 'cos' ||
          token === 'tan' ||
          token === 'ln' ||
          token === '%'
        ) {
          while (
            operators.length > 0 &&
            precedence[operators[operators.length - 1]] >= precedence[token] &&
            operators[operators.length - 1] !== '('
          ) {
            console.log(operators);
            const operator = operators.pop()
            const b = operands.pop()
            const a = operands.pop()
            operands.push(this.performOperation(a, b, operator))
          }
          console.log(token);
          operators.push(token)
        } else if (token === '(') {
          operators.push(token)
        } else if (token === ')') {
          console.log(operators);
          while (
            operators.length > 0 &&
            operators[operators.length - 1] !== '('
          ) {
            console.log(operators);
            const operator = operators.pop()
            const b = operands.pop()
            const a = operands.pop()
            operands.push(this.performOperation(a, b, operator))
          }
          if (operators.length > 0 && operators[operators.length - 1] === '(') {
            operators.pop()
          }
        } else {
          if (token.toLowerCase() === 'sci') {
            // 处理科学计数法
            const coefficient = parseFloat(operands.pop())
            const exponent = parseFloat(operands.pop())
            const result = coefficient * Math.pow(10, exponent)
            operands.push(result)
          } else {
            operands.push(parseFloat(token))
          }
        }
      }
    })
    while (operators.length > 0) {
      const operator = operators.pop()
      if (operator == 'sci') {
        const coefficient = parseFloat(operands.pop())
        const p = Math.floor(Math.log(coefficient) / Math.LN10);
        const n = coefficient * (10 ** -p);
        operands.push(`${n}e${p}`)
      }else{
        const b = operands.pop()
        let a = null
        console.log(operator);
        if (operator  != 'log' && operator  != 'sin' && operator  != 'cos'&& operator  != 'tan' && operator != 'ln') {
          a = operands.pop() 
        }
        operands.push(this.performOperation(a, b, operator))
      }
    }
    return operands[0].toString()
  },

  op: function (event) {
    const operator = event.currentTarget.dataset.op
    if(operator == 'ANS'){
      /**
       * 查看结果
       */
      if (!this.hadleFlag) {
        this.hadleFlag = true
        var that=this;
        wx.request({
          url: 'http://localhost:8088/calculator/getData', 
          method:'POST',
          data: {
            index: that.ansIndex
          },
          header: {
            'content-type': 'application/json' 
          },
          success (res) {
            that.hadleFlag = false
            if (that.ansIndex < 9) {
              that.ansIndex++ 
            }else{
              that.ansIndex = 0
            }
            if (res.data.message != null) {
              that.setData({
                result: res.data.message,
                completeCalculate: true,
              })
            }
          }
        }) 
      }
    }else if (!this.isOperatorEnd(this.data.result)) {
      if (this.data.result == 0) {
        this.setData({
          result: operator,
          completeCalculate: false,
        }) 
      }else{
        this.setData({
          result: this.data.result + operator,
          completeCalculate: false,
        })
      }
    }
  },

  performOperation: function (a, b, operator) {
    console.log(a,b,operator);
    switch (operator) {
      case '+':
        return parseFloat(a) + parseFloat(b)
      case '-':
        return parseFloat(a) - parseFloat(b)
      case '×':
        return parseFloat(a) * parseFloat(b)
      case '÷':
        return parseFloat(a) / parseFloat(b)
      case '%':
        return parseFloat(a) % parseFloat(b)
      case '^':
        return Math.pow(parseFloat(a), parseFloat(b))
      case '√':
        return Math.pow(parseFloat(b), 0.5)
      case 'sin':
        return Math.sin(parseFloat(b) * (Math.PI / 180))
      case 'cos':
        return Math.cos(parseFloat(b) * (Math.PI / 180))
      case 'tan':
        return Math.tan(parseFloat(b) * (Math.PI / 180))
      case 'log':
        return Math.log10(parseFloat(b))
      case 'ln':
        return Math.log(parseFloat(b))
      default:
        return 0
    }
  },

  isOperatorEnd: function (str) {
    if (typeof str !== 'string' || str.length === 0) {
      return false
    }
    const lastChar = str.charAt(str.length - 1)
    return false
  },

  numBtn: function (event) {
    const num = event.currentTarget.dataset.num
    if (this.data.completeCalculate) {
      this.setData({
        result: num,
        completeCalculate: false,
      })
    } else {
      if (this.data.result === '0' || this.data.result === 'Error: ') {
        this.setData({
          result: num,
        })
      } else {
        this.setData({
          result: this.data.result +''+ num,
        })
      }
    }
  },

  dot: function () {
    if (!this.data.result.includes('.') && !this.data.completeCalculate) {
      this.setData({
        result: this.data.result + '.',
      })
    }
  },

  cal: function () {
    if (!this.isOperatorEnd(this.data.result)) {
      const result = this.data.result
      try {
        const calculatedResult = this.calculate(result).toString()
        if (!this.hadleFlag) {
          this.hadleFlag = true
          var that=this;
          wx.request({
            url: 'http://localhost:8088/calculator/insertData', 
            method:'POST',
            data: {
              formula: result,
              answer: calculatedResult
            },
            header: {
              'content-type': 'application/json' 
            },
            success (res) {
              that.hadleFlag = false
              console.log(res.data)
            }
          }) 
        }

        this.setData({
          result: calculatedResult,
          completeCalculate: true,
          lastResult: calculatedResult,
        })
        this.data.history.push({ expression: result, result: calculatedResult })
        if (this.data.history.length > 10) {
          this.data.history.shift()
        }
        this.setData({ history: this.data.history })
      } catch (error) {
        this.setData({
          result: 'Error: ' + error.message,
          completeCalculate: true,
        })
      }
    }
  },

  clear: function () {
    this.setData({
      result: '0',
      completeCalculate: false,
      openedParentheses: 0,
      closedParentheses: 0,
    })
    this.ansIndex = 0
  },

  del: function () {
    if (this.data.result.length > 1) {
      this.setData({
        result: this.data.result.slice(0, -1),
      })
    } else {
      this.setData({
        result: '0',
      })
    }
  },
})

Back-end

(1) I am a Java back-end controller based on the Spring Boot framework, which is used by HTTP interface for receiving front-end requests and storing and reading data. The insertData method in CalculatorService is used to write calculation records into the database, and the getData method is used to query historical records. Use a ResultBean object to encapsulate the results of an operation, including status codes and messages, and return them to the front end.

package com.example.calculatordemo.controller;

import com.example.calculatordemo.bean.Record;
import com.example.calculatordemo.domain.GetDataParam;
import com.example.calculatordemo.domain.ResultBean;
import com.example.calculatordemo.service.CalculatorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculatorController {

    @Autowired
    private CalculatorService calculatorService;


    /**
     * 写入数据
     * @param record
     * @return
     */
    @PostMapping("/insertData")
    public ResultBean insertData(@RequestBody Record record) {
        return calculatorService.insertData(record);
    }

    /**
     * 查询数据
     * @param getDataParam
     * @return
     */
    @PostMapping("/getData")
    public ResultBean getData(@RequestBody GetDataParam getDataParam) {
        return calculatorService.getData(getDataParam);
    }
}
package com.example.calculatordemo.service.imp;

import com.example.calculatordemo.bean.Record;
import com.example.calculatordemo.domain.GetDataParam;
import com.example.calculatordemo.domain.ResultBean;
import com.example.calculatordemo.mapper.CalculatorMapper;
import com.example.calculatordemo.service.CalculatorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class CalculatorServiceImp implements CalculatorService {

    private static final Logger log = LoggerFactory.getLogger(CalculatorServiceImp.class);
    @Autowired
    private CalculatorMapper calculatorMapper;

    @Override
    @Transactional
    public ResultBean insertData(Record record) {
        ResultBean resultBean = new ResultBean();
        try {
            int raw = calculatorMapper.insertData(record);
            if (raw > 0) {
                resultBean.setCode(200);
            } else {
                resultBean.setCode(500);
                resultBean.setMessage("写入失败");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            resultBean.setCode(500);
            resultBean.setMessage(e.getMessage());
        }
        return resultBean;
    }


    @Override
    public ResultBean getData(GetDataParam getDataParam) {
        ResultBean resultBean = new ResultBean();
        try {
            resultBean.setCode(200);
            List<Record> recordList = calculatorMapper.getData();
            if (getDataParam.getIndex() < recordList.size()) {
                Record record = recordList.get(getDataParam.getIndex());
                resultBean.setMessage(record.getFormula() + "=" + record.getAnswer());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            resultBean.setCode(500);
            resultBean.setMessage(e.getMessage());
        }
        return resultBean;
    }
}

(2) I integrated the MySQL database as the back-end data store, while using MyBatis as the data access framework, so that the button returned the last calculation result, and view the history read the last ten string formula and the corresponding calculation result.

 

5. Personal Journey and Learnings

    Through this assignment, I gained valuable experience and skills and successfully made a computer application with front end separation. In this process, I have mastered the integration and use of Spring Boot framework, MyBatis data access framework and MySQL database. I successfully integrated the MySQL database into the application and realized the persistence of the data. This provides users with the ability to store calculation records, and also provides support for historical query.
    In summary, this assignment gave me a deep understanding of the application architecture of front-end separation, how to handle HTTP requests, store data in a database, and how to implement a powerful calculator application using different technical components. This is an important step for me in the field of full stack development, and I look forward to applying this knowledge and skills to future projects to continuously improve my development capabilities.

...全文
88 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
内容概要:本文提出一种基于融合鱼鹰搜索行为与柯西变异策略的改进麻雀优化算法(OCSSA),用于优化变分模态分解(VMD)的关键参数(如模态分量数K和惩罚因子α),以实现对滚动轴承振动信号的高效自适应分解,有效抑制模态混叠问题。经过OCSSA优化的VMD对原始信号进行预处理后,将分解得到的本征模态函数(IMF)重构为时频特征矩阵,作为卷积神经网络(CNN)的输入,以自动提取深层次的空间特征;随后,双向长短期记忆网络(BiLSTM)进一步挖掘特征序列中的前后向时序依赖关系,最终实现高精度的故障分类识别。该OCSSA-VMD-CNN-BiLSTM模型在西储大学公开轴承数据集上进行了充分验证,结果表明其在复杂噪声环境下对轴承不同故障类型与程度的诊断准确率显著优于传统方法,充分体现了智能优化算法与深度学习相结合在故障诊断领域的优越性能。; 适合人群:具备信号处理、机器学习及智能优化算法基础知识,从事机械装备状态监测、故障诊断、工业大数据分析等相关领域的科研人员、工程技术人员及高校研究生。; 使用场景及目标:①解决传统VMD参数依赖经验设定导致信号分解效果不稳定的问题;②提升强背景噪声和工况变化下滚动轴承早期微弱故障的检测灵敏度与分类准确率;③为智能制造和工业互联网背景下的关键设备智能运维与预测性维护提供一套可复现、高性能的技术解决方案。; 阅读建议:此资源以Matlab代码实现为核心,建议读者深入研读算法代码,重点理解OCSSA的寻优机制、VMD参数自适应选择过程以及CNN-BiLSTM的网络构建细节,通过复现完整实验流程,掌握从信号预处理、特征提取到智能分类的全流程关键技术,并尝试在自有数据集上进行迁移应用与性能对比。
源码链接: https://pan.quark.cn/s/a4b39357ea24 接口测试框架(基于json格式、http请求,python3,不兼容python2.x版本) 注:现在基于Excel文件管理测试用例基本实现,) 备注:大家在运行的时候,如果参数不需要key,只需要字典,可以在ddt_case.py和case.py改造parame,注释掉现在的parem,启用新的即可 依赖用例支持用例执行,在testCase的ddt_case.py有实现,逻辑在代码中有写,参数的格式{"name":"$case1=data"}即代表name的值是case1的data字段,简单的实现。 依赖用例是简单的实现,具体在业务上面还有很多复杂的要处理,知识实现了,部分的思路。 (目前在部分window上会出现FileNotFoundError [Errno 2] No such file or directory,这个bug是路径过长,解决方案为吧log日志放在当前目录,或者修改动态生成的文件的名字,给了第一种方式,测试日志放在当前目录) qq交流群:194704520 Alt text 使用的库 requests,绝大部分是基于Python原有的库进行的,这样简单方便, 使用脚本参数分离等思想,尽可能降低代码的耦合度。 如果你不配置钉钉机器人,注释到机器人相关的代码 首先我们来看下我们的目录 Alt text ### 1.Case文件夹用来存放我们的测试用例相关的, test_case用来存储我们的测试数据,Excel管理测试用例,yaml文件管理测试用例,后续要把yaml管理测试用例的也封装出来。 Interface对测试接口相关的封装,包括requests库,发送...

176

社区成员

发帖
与我相关
我的任务
社区描述
梅努斯软件工程
软件工程 高校 福建省·福州市
社区管理员
  • LinQF39
  • Jcandc
  • chjinhuu
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧