832302218_BoweiZheng_Front-End and Back-End Separated Calculator System_Assignment1

Acedir Acedir 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区

Front-End and Back-End Separated Calculator System

Student ID: 832302218
Name: Bowei Zheng
FZU/MU ID: 832302218/24127264
Course: EE308FZ


Table of Contents

2. Course Information

3. PSP Table

4. Presentation of the Finished Product

5. Design and Implementation Process

6. Code Explanation

7. Personal Journey and Learnings


Deployment:


2. Course Information

ItemContent
CourseSoftware Engineering / Web Development (fill in as appropriate)
Assignment RequirementsBuild a front-end and back-end separated calculator system with basic calculation, compound expressions, history, and history deletion
ObjectivesUnderstand front-end/back-end separation, REST API design, expression parsing, and database persistence
Other ReferencesOriginal assignment: https://bbs.csdn.net/topics/620530837

3. PSP Table

PhaseEstimated (min)Actual (min)
Requirement Analysis3060
System Design4060
Backend – Project Skeleton2040
Backend – Expression Parser90100
Backend – Calculation API3040
Backend – Database & History Module6070
Frontend – UI6090
Frontend – API Integration6080
Frontend/Backend Integration4060
Testing4060
Deployment4060
Blog Writing12090
Total630810

4. Presentation of the Finished Product

All screenshots below are taken from the actual running project.

4.1 Main Interface

​

4.2 Addition

​

4.3 Subtraction

​

4.4 Multiplication

​

4.5 Division

​

4.6 Decimal Calculation

​

4.7 Compound Expression with Parentheses

​

4.8 Unary Minus

​

4.9 Percentage

​

4.10 Division by Zero

​

4.11 Invalid Expression

​

4.12 Calculation History and Persistence

​

4.13 Delete a History Record

​


5. Design and Implementation Process

5.1 Requirement Analysis

The assignment requires a calculator system using a front-end and back-end separated architecture. The frontend is only responsible for UI, input, and sending requests. The backend performs expression parsing, calculation, exception handling, and history storage. Required features include basic arithmetic, compound expressions with parentheses and unary signs, history queries, and history deletion.

5.2 System Architecture

┌──────────────────┐
│  Frontend (Web)                   │
│  HTML + CSS + JS               │
└────────┬─────────┘
                       │  HTTP / JSON
                      ▼
┌──────────────────┐
│  Backend (Flask)                   │
│  Parser / Calc                        │
│  History Module                     │
└────────┬─────────┘
                       │  SQL
                      ▼
┌──────────────────┐
│ Database (SQLite)                │
│ calculation_                           │
│ history table                          │
└──────────────────┘

5.3 Functional Structure Diagram

Calculator System
├── Calculation
│   ├── Basic Operations (+ - × ÷)
│   ├── Compound Expressions (precedence, parentheses)
│   ├── Unary Plus/Minus
│   ├── Decimals
│   ├── Percentage
│   └── Exception Handling (division by zero, invalid expression)
├── History
│   ├── Save History
│   ├── Query History
│   ├── Delete One Record
│   └── Clear All
├── Frontend
│   ├── User Input
│   ├── Result Display
│   ├── History Display
│   └── Error Message
└── Backend
    ├── API Endpoints
    ├── Expression Parser
    ├── Calculation Service
    └── Database

5.4 API Design

MethodEndpointDescription
POST/api/calculateSubmit an expression, return result
GET/api/historyQuery history records
DELETE/api/history/{id}Delete a specific record
DELETE/api/history

Clear all history

Success Response:

{ "success": true, "expression": "1+2", "result": 3 }

Error Response:

{ "success": false, "message": "Divisor cannot be zero" }

5.5 Database Design

Table: calculation_history

FieldTypeDescription
idINTEGERPrimary key, auto-increment
expressionTEXTCalculation expression
resultTEXTCalculation result
created_atTEXTCalculation time, YYYY-MM-DD HH:MM:SS

5.6 Calculation Module Design

The core is a recursive descent parser that splits expressions into four grammar levels:

expression := term (('+' | '-') term)*
term       := factor (('*' | '/') factor)*
factor     := ('+' | '-') factor | primary
primary    := NUMBER | '(' expression ')'

Precedence Handling: Multiplication/division are handled in the inner term layer, addition/subtraction in the outer expression layer, naturally achieving "multiplication/division before addition/subtraction".

Unary Signs: Handled in the factor layer.

5.7 Exception Handling

ExceptionHandling
Illegal character (abc)CalcError raised during tokenization
Mismatched parenthesesChecked during parsing
Division by zeroChecked in term layer
Empty expressionChecked before parsing
Result too largeChecked after parsing (abs(result) > 1e15)

All CalcError exceptions are caught in app.py and returned with HTTP 400.

5.8 Frontend/Backend Interaction

User inputs expression
            ↓
Frontend sends POST /api/calculate
            ↓
Backend: tokenize → parse → calculate
            ↓
Success: write to DB → return {success, result, record}
Failure: return {success: false, message}
            ↓
Frontend updates result area → re-fetches GET /api/history
            ↓
Renders history list

5.9 Deployment

  • Backend deployed on PythonAnywhere: git clone → create virtualenv → configure WSGI → Reload.

  • Frontend deployed on Netlify Drop: drag the src folder → get a public URL.

  • API_BASE is updated to the backend's public URL for cross-origin access.


6. Code Explanation

6.1 Frontend API Call (app.js)

const API_BASE = "https://acedir832302218.pythonanywhere.com";

async function doCalculate() {
    const expression = expressionInput.value.trim();
    const res = await fetch(`${API_BASE}/api/calculate`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ expression }),
    });
    const data = await res.json();
    if (!data.success) {
        resultEl.textContent = "Error: " + data.message;
        return;
    }
    resultEl.textContent = "= " + data.result;
}

Explanation: The frontend only sends the expression string and does not perform any calculation. The result from the backend is displayed directly. This ensures all core logic is on the backend.

6.2 Result Retention Interaction

let justCalculated = false;

if (justCalculated && /^[0-9.]$/.test(value)) {
    // Just calculated, user pressed a digit → clear and start new input
    expressionInput.value = "";
    resultEl.textContent = "";
}

Explanation: The justCalculated flag implements "keep the expression and result after =, clear only when a new digit is entered".

6.3 Tokenization (calculator.py)

def tokenize(expr):
    tokens = []
    i = 0
    while i < len(expr):
        ch = expr[i]
        if ch.isspace():
            i += 1
            continue
        if ch in "+-*/×÷":
            op = {"×": "*", "÷": "/"}.get(ch, ch)
            tokens.append(Token(Token.OP, op))
            i += 1
            continue
        if ch == "%":
            tokens.append(Token(Token.OP, "/"))
            tokens.append(Token(Token.NUMBER, 100))
            i += 1
            continue
        # ...numbers and parentheses...
    return tokens

Explanation: × is mapped to *, ÷ to /, so the frontend can send Chinese symbols directly. % is converted to /100.

6.4 Recursive Descent Calculation

def parse_expression(self):
    left = self.parse_term()
    while self.peek() and self.peek().value in ("+", "-"):
        op = self.consume().value
        right = self.parse_term()
        left = left + right if op == "+" else left - right
    return left

Explanation: parse_expression handles addition/subtraction, parse_term handles multiplication/division. Since multiplication/division is called at a deeper layer, it is evaluated first, matching mathematical precedence.

6.5 Database Insertion

def insert_history(expression, result):
    created_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    conn = get_conn()
    cur = conn.execute(
        "INSERT INTO calculation_history (expression, result, created_at) VALUES (?, ?, ?)",
        (expression, str(result), created_at),
    )
    conn.commit()
    return {"id": cur.lastrowid, "expression": expression, "result": result, "created_at": created_at}

Explanation: Parameterized SQL (?) is used to prevent injection. The newly created record is returned for the frontend.

6.6 Delete API

@app.route("/api/history/<int:record_id>", methods=["DELETE"])
def api_history_delete(record_id):
    deleted = db.delete_history(record_id)
    if not deleted:
        return fail("Record not found", 404)
    return ok({"deleted_id": record_id}, 200)

 

Explanation: The deleted ID is returned so the frontend can re-query the latest history.


7. Personal Journey and Learnings

7.1 Problems and Solutions

Problem 1: I initially wanted to use Python's eval for a quick solution, but the assignment explicitly forbids it.

Solution: I learned recursive descent parsing and implemented a four-layer grammar to handle precedence. It took longer, but completely avoids code injection.

Problem 2: CORS errors when the frontend called the backend.

Solution: The backend uses flask-cors with a single CORS(app) line.

Problem 3: The SQLite database file was accidentally committed to Git.

Solution: Added .gitignore to exclude calculator.db, and used git rm --cached to remove it from version control.

Problem 4: After deployment on PythonAnywhere, python app.py reported port conflict.

Solution: PythonAnywhere uses its own Web App hosting mechanism; manual startup is not needed. Configuring the WSGI file and clicking Reload is sufficient.

7.2 What I Learned

  • REST API design and HTTP status codes

  • Recursive descent parsing

  • Front-end/back-end separation responsibilities

  • SQLite parameterized queries and injection prevention

  • Git branch management and GitHub workflow

  • Cloud deployment (PythonAnywhere + Netlify)

7.3 Possible Improvements

  • Add a user system for independent history per user

  • Add history search and pagination

  • Add keyboard shortcut support

  • Add rate limiting to the backend

...全文

相关推荐

基于MATLAB的复合弹性模量分析,采用混合法则,结合纤维体积分数变化和图形结果。.zip

1.版本:matlab2014a/2019b/2024b 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

海神之光

基于MATLAB的自适应纯追踪曲线跟踪机器人仿真,采用多路径、自适应速度控制和图形界面可视化。.zip

1.版本:matlab2014a/2019b/2024b 2.附赠案例数据可直接运行。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

海神之光

【数据库优化】通信行业B/O域查询性能提升:基于分区裁剪与覆盖索引的秒级溯源系统实现

内容概要:本文围绕通信行业中海量话单与信令数据的查询性能问题,系统阐述了从全表扫描到秒级响应的数据库优化路径。文章以运营商 cdr_detail 表为案例,揭示了因使用函数操作索引列(如DATE(call_start_time))和深分页(LIMIT offset, size)导致的全表扫描问题,并提出完整的优化方案:通过时间范围RANGE分区实现分区裁剪、构建msisdn与时间的联合覆盖索引、消除索引列函数运算、采用游标分页替代OFFSET等方式,使查询性能从P95 8.3秒降至290毫秒。同时介绍了执行计划分析(EXPLAIN)在调优中的关键作用,并展望了HTAP架构、向量化执行与AI自治优化器等未来方向。; 适合人群:具备一定数据库基础知识,从事通信行业数据开发、DBA或后端研发的技术人员,尤其是面对大规模时序数据查询性能瓶颈的工程师;; 使用场景及目标:①解决营业厅用户详单查询、网间结算对账、VoNR信令分析等高并发、低延迟查询场景下的性能问题;②掌握如何通过分区策略、索引设计和SQL改写实现从全表扫描到精准索引访问的优化落地; 阅读建议:建议结合实际生产环境中的大表查询案例,对照本文的反例与正例进行执行计划对比分析,并在测试环境中实践分区表创建、覆盖索引构建及游标分页改写,深入理解每项优化技巧的实际效果。

智能化咨询

石墨提纯全球市场结构与产业发展趋势分析报告(QYResearch最新研究).docx

石墨提纯全球市场结构与产业发展趋势分析报告(QYResearch最新研究)

行业报告QY

政府科技管理者如何提升科技成果转化政策的精准匹配与执行效率?.docx

政府科技管理者如何提升科技成果转化政策的精准匹配与执行效率?

BIZKEEN
评论
收藏 已收藏
分享
返回顶部
Acedir
2601_FZU-MU_SE 173 成员 138 内容