第二次作业——前后端交互计算器

基于html+css+javascript 使用flask

这个作业属于哪个课程软件工程
这个作业要求在那里作业要求
课程目标将计算器实现前后端分离
其他参考文献

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

GitCode链接

PSP表格

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

成品展示

基本运算

计算器基础计算

科学运算

计算器科学运算

清零回退

计算器清零回退

查看历史记录

计算器查看历史记录

捕捉异常

计算器捕捉异常

设计实现过程

设计思想

这个计算器的设计思想基于MVC(模型-视图-控制器)架构模式,将应用程序分为三个互相关联的部分。

  1. 模型(Model):
    数据存储: 使用SQLite数据库和SQLAlchemy ORM存储计算结果。每次计算都会存储,以便以后可以访问。
    数据结构: 设计了一个简单的数据库模型,包含表达式和其计算结果。
  2. 视图(View):
    用户界面: 通过HTML和CSS创建了用户界面,包括数字、操作符和其他功能的按钮。
    输出显示: 使用一个输出框来显示用户的输入和计算结果。
  3. 控制器(Controller):
    逻辑处理: JavaScript和jQuery被用于处理用户的输入,管理和执行计算。
    与后端通信: 通过AJAX与后端交互,获取计算结果或最新的计算历史。

设计思想:

  1. 模块化:
    代码被模块化,使其易于理解和维护。HTML负责结构,CSS负责样式,JavaScript负责功能和逻辑。
  2. 交互性:
    通过JavaScript和jQuery,实现了与用户的动态交互。用户可以实时地输入、修改表达式,并得到实时的反馈。
    扩展性:
    由于采用了MVC架构,所以可以在不影响其他部分的情况下修改或添加新功能。
  3. 安全性:
    虽然在后端使用了eval()函数,但设计时也考虑了安全性。可以进一步优化以减少潜在风险。
  4. 用户友好:
    设计了直观且用户友好的界面,提供了清晰的用户指导,易于使用。

前端

HTML:
创建了计算器的布局,包括输出框和各种按钮(数字,操作符,特殊符号等)。
CSS:
用于美化计算器的界面,例如设置边框、颜色、阴影等。
JavaScript 和 jQuery:
事件处理: 为计算器的每个按钮添加点击事件处理函数。
操作队列 (operationQueue): 用于存储用户输入的数字和操作符。
AJAX 请求:
当用户点击“=”按钮时,一个POST请求会发送到后端,请求计算表达式的结果。
当用户点击“ans”按钮时,一个GET请求会发送到后端,请求历史计算结果。

后端

数据库模型(SQLite 和 SQLAlchemy):
一个简单的数据库模型被创建,用于存储计算表达式和它们的结果。
路由和视图函数:
‘/’ (首页): 返回包含计算器界面的HTML页面。
‘/latest’ (获取最新结果): 返回数据库中的最新计算结果。
‘/calculate’ (计算表达式): 计算一个数学表达式的结果,并将其和表达式存储在数据库中

前后端通信

计算器应用的前后端通信主要通过HTTP请求实现,具体包括如下几个步骤:

  1. 用户输入和计算请求(前端):
    用户在前端的HTML页面中输入数学表达式,并点击等于(=)按钮。
    JavaScript(JS)捕获用户的输入,并处理这些输入,准备发送到后端。
  2. 发送请求到后端(前端->后端):
    JS使用AJAX(异步JavaScript和XML)发送POST请求到后端。这个请求包含用户输入的数学表达式。
    请求是发送到/calculate端点的,由Flask(后端框架)处理。
  3. 后端处理(后端):
    Flask接收到POST请求和用户输入的数学表达式后,进行处理和计算。
    计算的结果或任何错误信息将作为响应返回到前端。
  4. 接收和处理后端的响应(前端):
    前端的JS接收到后端的响应,根据响应内容更新前端界面。
    如果计算成功,显示计算结果;如果有错误,显示错误消息。
  5. 获取最新的计算结果(前端->后端):
    用户还可以通过点击ans按钮获取最新的计算结果。
    点击ans按钮时,JS会发送一个GET请求到/latest端点。
    后端处理这个请求,查询数据库并返回最新的计算结果。
  6. 显示最新的计算结果(前端):
    前端接收到包含最新计算结果的响应,并在界面上显示。

数据库存储

  1. 数据库和表的设置(Initialization):
    在 Flask 应用中配置数据库的 URI。
    定义一个 SQLAlchemy 模型 CalculationResult,它包含了表达式和结果的列。
    当应用启动时,如果还没有创建数据库和表,将会自动创建。
  2. 执行计算(Calculation):
    用户在前端输入一个数学表达式并请求计算。
    后端接收这个请求,计算表达式,并准备存储结果。
  3. 存储计算结果(Storing the Results):
    创建一个新的 CalculationResult 对象,用于存储表达式和它的计算结果。
    将这个新对象添加到数据库会话中,并提交会话。
    这样,新的计算结果就被保存到数据库中了。
  4. 查询历史计算结果(Querying the Latest Result):
    当用户请求历史计算结果时,应用会查询数据库,数据库按照 ID 降序排序结果,并返回第一个结果,即最新的计算结果。
  5. 返回结果到前端(Returning the Result to the Frontend):
    应用将查询到的最新计算结果返回到前端,前端再显示给用户。

关键代码

前端(HTML + JavaScript)

  1. HTML 结构:
    为每个按钮创建 HTML 元素,并分配特定的 CSS 类和 onclick 事件处理程序。
    用于显示当前表达式的输出文本框。
<button class="button number-button" onclick="appendNumber('1')">1</button>
<button class="button operation-button" onclick="calculate()">=</button>
  1. JavaScript 函数:
    appendNumber、appendOperation 等函数用于处理用户输入。
    calculate 函数用于向后端发送计算请求。
    appendLatestResult 函数用于从后端获取并显示最新的计算结果。
function appendNumber(number) {
        let lastElement = operationQueue[operationQueue.length - 1];
        if (!isNaN(lastElement) || lastElement === '.') {
            operationQueue[operationQueue.length - 1] += number;
        } else {
            operationQueue.push(number);
        }
        updateDisplay();
    }
function calculate() {
    let calculation = operationQueue.join('');
    $.post("/calculate", { expression: calculation }, function(data) {
        if (data.error) {
            alert(data.error);
        } else {
            operationQueue = [data.result.toString()];
            updateDisplay();
        }
    });
}
async function appendLatestResult() {
    try {
        let response = await fetch('/latest');
        let data = await response.json();

        if (data.result !== undefined) {
            operationQueue.push(data.result.toString()); // 修改这里
            updateDisplay();
        } else {
            alert("No history available");
        }
    } catch (error) {
        console.error("Error while fetching the latest result:", error);
    }
}
}

后端(Python + Flask)
3. 数据库模型:
定义 CalculationResult 模型,用于在数据库中存储计算结果。

class CalculationResult(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    expression = db.Column(db.String(200), nullable=False)
    result = db.Column(db.Float, nullable=False)
  1. 路由和控制器:
@app.route('/calculate', methods=['POST']) 定义了处理计算请求的路由。
@app.route('/latest', methods=['GET']) 定义了返回最新计算结果的路由。

这个路由处理获取最新计算结果的请求。

数据库查询:CalculationResult.query.order_by(CalculationResult.id.desc()).first() 从数据库中检索最新(最后)的计算结果。
返回值: 如果数据库中有计算结果,它将返回最新的计算结果;如果没有,它将返回一个错误消息。

app.route('/latest', methods=['GET'])
def get_latest_result():
    latest_result = CalculationResult.query.order_by(CalculationResult.id.desc()).first()
    if latest_result:
        return jsonify({"result": latest_result.result})
    else:
        return jsonify({"error": "No history available"})

这个路由处理计算表达式的请求。
获取表达式: 使用 request.form.get(‘expression’) 从 POST 请求中获取用户输入的表达式。
处理表达式: 代码替换了 “Math.sin”, “Math.cos”, “Math.tan”, 和 “Math.log” 为 Python 的 math 模块对应的函数,以便可以正确计算。
执行计算: 使用 Python 的 eval() 函数执行计算。请注意,使用 eval() 函数有安全风险。
保存结果: 将计算结果保存到数据库中。
返回值: 如果计算成功,它将返回计算结果;如果有错误(例如,表达式不合法),它将返回一个错误消息。


@app.route('/calculate', methods=['POST'])
def calculate_expression():
    try:
        expression = request.form.get('expression')

        # Map the incoming expression to use Python's math module functions
        expression = expression.replace("Math.sin", "math.sin")
        expression = expression.replace("Math.cos", "math.cos")
        expression = expression.replace("Math.tan", "math.tan")
        expression = expression.replace("Math.log", "math.log")

        # Caution: eval() is dangerous
        result = eval(expression)

        # Save the result to the database
        calculation = CalculationResult(expression=expression, result=result)
        db.session.add(calculation)
        db.session.commit()

        return jsonify({"result": result})
    except Exception as e:
        return jsonify({"error": str(e)})

心路历程和收获:

学习和探索: 在实现过程中,我学习了如何使用HTML和CSS来布局和样式化页面,了解并实践了JavaScript在浏览器中的应用,如操作DOM,事件处理等。学习了如何使用Flask框架构建后端服务,处理HTTP请求,如何使用Flask配置路由和编写处理请求的视图函数。
困难与挫折: 在处理安全性和数据库操作时,遇到了一些困难,但通过不断学习和尝试,最终找到了解决方法。
通过这个项目,我不仅实践了前后端开发的知识,也学到了很多项目管理和问题解决的方法,是一次非常宝贵的经验。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值