832302218_BoweiZheng_Front-End and Back-End Separated Calculator System_Assignment1
Front-End and Back-End Separated Calculator System
Student ID: 832302218
Name: Bowei Zheng
FZU/MU ID: 832302218/24127264
Course: EE308FZ
Table of Contents
1. Git Repository and Code Standard Links
4. Presentation of the Finished Product
5. Design and Implementation Process
7. Personal Journey and Learnings
1. Git Repository and Code Standard Links
-
Frontend Repository: GitHub - Acedir/832302218_calculator_frontend · GitHub
-
Backend Repository: GitHub - Acedir/832302218_calculator_backend · GitHub
-
Frontend Code Standard: https://github.com/Acedir/832302218_calculator_frontend/blob/main/codestyle.md
-
Backend Code Standard: 832302218_calculator_backend/codestyle.md at main · Acedir/832302218_calculator_backend · GitHub
Deployment:
-
Frontend URL: 前后端分离计算器
-
Backend URL: https://Acedir.pythonanywhere.com
2. Course Information
| Item | Content |
|---|---|
| Course | Software Engineering / Web Development (fill in as appropriate) |
| Assignment Requirements | Build a front-end and back-end separated calculator system with basic calculation, compound expressions, history, and history deletion |
| Objectives | Understand front-end/back-end separation, REST API design, expression parsing, and database persistence |
| Other References | Original assignment: https://bbs.csdn.net/topics/620530837 |
3. PSP Table
| Phase | Estimated (min) | Actual (min) |
|---|---|---|
| Requirement Analysis | 30 | 60 |
| System Design | 40 | 60 |
| Backend – Project Skeleton | 20 | 40 |
| Backend – Expression Parser | 90 | 100 |
| Backend – Calculation API | 30 | 40 |
| Backend – Database & History Module | 60 | 70 |
| Frontend – UI | 60 | 90 |
| Frontend – API Integration | 60 | 80 |
| Frontend/Backend Integration | 40 | 60 |
| Testing | 40 | 60 |
| Deployment | 40 | 60 |
| Blog Writing | 120 | 90 |
| Total | 630 | 810 |
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
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/calculate | Submit an expression, return result |
| GET | /api/history | Query 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
| Field | Type | Description |
|---|---|---|
| id | INTEGER | Primary key, auto-increment |
| expression | TEXT | Calculation expression |
| result | TEXT | Calculation result |
| created_at | TEXT | Calculation 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
| Exception | Handling |
|---|---|
Illegal character (abc) | CalcError raised during tokenization |
| Mismatched parentheses | Checked during parsing |
| Division by zero | Checked in term layer |
| Empty expression | Checked before parsing |
| Result too large | Checked 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
srcfolder → get a public URL. -
API_BASEis 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最新研究)
政府科技管理者如何提升科技成果转化政策的精准匹配与执行效率?.docx
政府科技管理者如何提升科技成果转化政策的精准匹配与执行效率?


