Gin,Gorm实现Web计算器

news2024/9/22 12:28:01

目录

        • 仓库链接
        • 0.PSP表格
        • 1. 成品展示
          • 1.基础运算
          • 2. 清零回退
          • 3.错误提示
          • 4.历史记录
          • 拓展功能
            • 1.前端可修改的利率计算器
            • 2.科学计算器
            • 3. 按钮切换不同计算器模式
            • 4.用户在一次运算后不清零继续输入操作符,替换表达式为上次答案
        • 2.设计实现过程
        • 3.代码说明
        • 4.心路历程和收获

仓库链接
2301-计算机学院-软件工程https://bbs.csdn.net/forums/ssynkqtd-05
这个作业要求在哪里https://bbs.csdn.net/topics/617377308
这个作业的目标实现一个前后端分离计算器
其他参考文献

backend
frontend
Google 开源项目风格指南——中文版
Google Style Guides

0.PSP表格
PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划4020
• Estimate估计这个任务需要多少时间1010
Development开发650630
• Analysis需求分析 (包括学习新技术)4030
• Design Spec生成设计文档8075
• Design Review设计复审3545
• Coding Standard代码规范 (为目前的开发制定合适的规范)2520
• Design具体设计3530
• Coding具体编码325320
• Code Review代码复审6560
• Test测试(自我测试,修改代码,提交修改)6050
Reporting报告9590
• Test Report测试报告2520
• Size Measurement计算工作量1015
• Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划4555
合计670630
1. 成品展示
1.基础运算

在这里插入图片描述

2. 清零回退

在这里插入图片描述

3.错误提示

在这里插入图片描述

4.历史记录

在这里插入图片描述

拓展功能
1.前端可修改的利率计算器

在这里插入图片描述

2.科学计算器

在这里插入图片描述

3. 按钮切换不同计算器模式

在这里插入图片描述

4.用户在一次运算后不清零继续输入操作符,替换表达式为上次答案

在这里插入图片描述

2.设计实现过程
  1. 前端:前端需要在上一轮作业的基础上加以完善。首先要扩充为两个输入框,一个用于显示用户输入的表达式,一个用于显示答案。同时在上一轮的form基础上再做一个利率计算器(利率计算器和存款计算器可以共用一个div)。同时使用fetch向后端传发数据。
  2. 后端:后端使用Gin做Web框架。通过路由组和hander接前端请求。Gin相比于Hertz是一个轻量级的框架适合做这种小项目。数据库交互用Gorm。
  3. 数据库:只用到了Mysql。存历史记录,存款、贷款三张表。暂且把这个计算器看作单机版本,所以在存历史记录的时候没有特意区分不同用户ID。可视化工具推荐Dbeaver。
3.代码说明
  1. 前端采用fetch通信。fetch的语法很简明,不再赘述。以查询历史记录为例:
function ans() {
    fetch("http://localhost:8080/history/", {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json'
        },
    })
        .then(response => response.json())
        .then(data => {
            // 处理后端的响应
            if (data.code === 200) {
                const expVal = data.result;

                if (expVal.length > 0) {
                    const displayText = expVal.map((item, index) => `
          <div class="expression-container" id="expression-${index}">
            $ ${item.Exp} = ${item.Val} $
          </div>
        `).join('<br>');

                    Swal.fire({
                        title: '历史记录(近 10 条)',
                        html: displayText,
                        icon: 'success',
                        confirmButtonText: '关闭'
                    });

                    // 使用MathJax渲染数学表达式
                    for (let i = 0; i < expVal.length; i++) {
                        MathJax.Hub.Queue(["Typeset", MathJax.Hub, `expression-${i}`]);
                    }

                } else {
                    // 如果没有之前的数据,显示提示消息
                    Swal.fire('没有可显示的数据', '', 'error');
                }
            } else {
                // code 不为 200,给出提示
                console.error(`响应状态不是 200,错误消息:${data.msg}`);
            }
        })
        .catch(error => {
            console.error("An error occurred while receiving the result from the backend: " + error);
        });
}

页面的切换用一个变量来控制,相当于一个mod 3 的加法,控制div的可见性。

function mode() {
    st = (st + 1) % 3;
    const normalCalculator = document.querySelector('.normal');
    const interestCalculator = document.querySelector('.interest');
    let bt = document.getElementById("topMode");

    var updateInter = document.getElementById("update_inter");
    var updateInter2 = document.getElementById("update_inter2");
    if (st === 0) {
        normalCalculator.style.display = 'block';
        interestCalculator.style.display = 'none';
        bt.innerHTML = "科学计算器"
    } else if (st === 1) {
        normalCalculator.style.display = 'none';
        interestCalculator.style.display = 'block';
        updateInter.style.display = "block";
        updateInter2.style.display = "none";
        bt.innerHTML = "存款计算器"
    } else if (st === 2) {
        normalCalculator.style.display = 'none';
        interestCalculator.style.display = 'block';
        updateInter2.style.display = "block";
        updateInter.style.display = "none";
        bt.innerHTML = "贷款计算器"
    }
}
  1. 后端启动服务:
package main

import (
	"WebCalculator/dal/mysql"
	"WebCalculator/router"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

func main() {
	mysql.Init()
	r := gin.Default()
	// 解决跨域问题
	r.Use(cors.Default())
	router.SetUpRoutes(r)
	err := r.Run(":8080")
	if err != nil {
		panic(err)
	}
}

注意需要解决跨域问题。查阅资料得知最近的Gin官方已经给出了对于跨域的问题的默认配置无需再手动配置,一行代码就可以了。同时在main函数中初始化mysql相关链接信息和路由组。

func SetUpRoutes(engine *gin.Engine) {
	home := engine.Group("/")
	{
		home.GET("/hello", hello.Hello)
	}
	his := engine.Group("/history")
	{
		his.POST("/", history.AddHistory)
		his.GET("/", history.QueryHistory)
	}
	dep := engine.Group("/deposit")
	{
		dep.POST("/", deposit.UpdateDep)
		dep.GET("/", deposit.QueryInterest)
	}
	l := engine.Group("/loans")
	{
		l.GET("/", loans.QueryInterest)
		l.POST("/", loans.UpdateLoans)
	}
}

hander包编写具体实现方法。
以查询利息为例:

func QueryInterest(c *gin.Context) {
	// 获取查询参数
	principalStr := c.DefaultQuery("principal", "")
	durationStr := c.DefaultQuery("duration", "")

	// 将字符串转换为浮点数
	principal, err1 := strconv.ParseFloat(principalStr, 64)
	duration, err2 := strconv.ParseFloat(durationStr, 64)

	if err1 != nil || err2 != nil {
		// 处理转换错误,例如返回错误响应
		c.JSON(http.StatusOK, gin.H{
			"code": 400,
			"msg":  "输入无效",
		})
		return
	}

	interest := service.CalInterest(entity.MoneyCal{
		Money:    principal,
		Duration: duration,
	}, 1)
	c.JSON(http.StatusOK, gin.H{
		"code":   200,
		"msg":    "计算成功",
		"result": interest,
	})

}

注意存款和贷款的逻辑几乎相同。所以可以增加一个传入参数op,0/1表示不同类型就可以复用计算函数。

func ExistDuration(duration float64, op int) bool {
	if op == 1 {
		result := mysql.DB.Where("duration = ?", duration).First(&entity.Deposit{})
		return result.Error != gorm.ErrRecordNotFound
	}
	result := mysql.DB.Where("duration = ?", duration).First(&entity.Loan{})
	return result.Error != gorm.ErrRecordNotFound
}

func CalInterest(cal entity.MoneyCal, op int) float64 {
	duration := cal.Duration
	money := cal.Money

	if op == 1 {
		var deposit entity.Deposit
		mysql.DB.Where("duration <= ?", duration).Order("duration desc").Limit(1).First(&deposit)
		return money * deposit.Rate / 100
	}

	var loans entity.Loan
	mysql.DB.Where("duration <= ?", duration).Order("duration desc").Limit(1).First(&loans)
	return money * loans. Rate / 100
}

3.数据库
Gorm的数据库操作十分便利。提供了AutoMigrate来自动迁移表结构。有结构体的情况下可以自动建对应表.无需编写sql。

DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		SkipDefaultTransaction: true,
		PrepareStmt:            true,
		Logger:                 logger.Default.LogMode(logger.Info),
	})
	if err != nil {
		panic(err)
	}

	err = DB.AutoMigrate(&entity.History{}, &entity.Deposit{}, &entity.Loan{})
	if err != nil {
		return
	}

且gorm.Model包含许多实用信息,ID,CT,UPT等等。

4.心路历程和收获

后端部分其实没啥技术含量,主要是CRUD…
感觉最难的部分还是在前端,因为之前不会,所以几乎是一直在对着已有的HTML和CSS代码不断增删猜测效果/询问他人。感觉前端代码实在写的不堪入目,还好最后效果感觉还行。
有些疑惑为什么要一个人完成前后端,可能全栈是学院派的宿命。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1080219.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型/LLM的涌现能力

新浪张俊林–中国人工智能学会演讲 文章目录 什么是大模型的涌现能力LLM表现的涌现能力1. In Context Learning -- 情景学习2. CoT3. 其他涌现能力 LLM模型规模和涌现能力的关系模型训练中的顿悟现象&#xff1a;GrokkingLLM涌现能力的可能原因 什么是大模型的涌现能力 涌现&a…

message“: “CSRF token mismatch

tableData&#xff0c;noticeData 是两个长二维数组 $.ajax({url: "/admin/samproofing/confirmPieces",type: "POST",data: {"ym": ym1,"papertype":paper_type,"person_data": that.tableData,"notice_data": t…

Servlet入门

URL和URI&#xff1a; URL统一资源定位符&#xff0c;表示对外暴露的整个网址 URI统一资源标示符&#xff0c;表示资源的访问路径&#xff0c;与servlet绑定的地址 HTTP请求结构&#xff1a; HTTP请求包含三部分&#xff1a;请求行、请求头、请求体 请求行包含&#xff1a;请…

被替换掉的文件如何找回来?

当我们在编辑文件时&#xff0c;通常会直接保存而不是另存为新文件&#xff0c;这样会替换原始文件的信息。如果需要对原始文件进行二次编辑&#xff0c;情况就会比较复杂。那么被替换掉的文件还能找回来吗&#xff1f; 被替换的文件是否可以恢复&#xff1f; 这取决于替换原始…

【论文笔记】A theory of learning from different domains

防盗 https://www.cnblogs.com/setdong/p/17756127.html domain adaptation 领域理论方向的重要论文. 这篇笔记主要是推导文章中的定理, 还有分析定理的直观解释. 笔记中的章节号与论文中的保持一致. 1. Introduction domain adaptation 的设定介绍: 有两个域, source domain…

智慧空开让用电更安全、管理更智能——电脑APP远程控制开合闸

安科瑞 崔丽洁 01 什么是低压断路器&#xff1f;低压断路器的定义是&#xff1a;能够接通、承载及分断正常电路条件下的电流&#xff0c;也能在规定的非正常电路条件&#xff08;过载、短路、特别是短路&#xff09;下接通、承载一定时间和分断电流的开关电器。 断路器的分类&…

go语言教程4:switch和map

文章目录 switchswitch匹配字典 go语言教程&#xff1a;安装入门➡️for循环➡️数组、切片和指针 switch和map&#xff0c;一个是控制流&#xff0c;一个是数据结构&#xff0c;之所以把两个不同类型的知识点放在一起讲解&#xff0c;是因为二者有着极其相似的运行逻辑&#…

WSL+vscode配置miniob环境

1.配置WSL Windows Subsystem for Linux入门&#xff1a;安装配置图形界面中文环境vscode wu-kan 2.获取源码 找个位置Git Bash然后拉取代码 git clone https://github.com/oceanbase/miniob.git 3.安装相关依赖 https://gitee.com/liangcha-xyy/source/blob/master/how…

Spring Boot Bean 注入的常用方式教程

Spring Boot Bean 注入是一种将依赖对象引入到应用程序组件中的机制&#xff0c;它有助于实现松耦合和可测试的代码。这种注入方式允许我们将依赖关系委托给 Spring 容器来管理&#xff0c;从而提高了代码的可维护性和可读性。Spring Boot 提供了多种 Bean 注入方式&#xff0c…

qt判断当前日期的当月的最后一天是几号

1、拖个dateTimeEdit在界面上&#xff0c;同时来判断输入的时间的最后一天的日期是什么&#xff1f; int year,month;int monthArr[12]{31,28,31,30,31,30,31,31,30,31,30,31};QDateTime time ui->dateTimeEdit->dateTime();year time.toString("yyyy").toIn…

C++入门介绍

1.C入门知识 以下是一些 C 入门知识&#xff1a; C 是一种面向对象的编程语言&#xff0c;它具有高效、灵活、可移植性好等特点 C 中的基本数据类型包括整型、浮点型、字符型等 C 中的控制语句包括条件语句&#xff08;if、else&#xff09;、循环语句&#xff08;for、while、…

飞凌嵌入式成为“龙芯生态伙伴计划”认证级企业!

近日&#xff0c;飞凌嵌入式正式成为“龙芯生态伙伴计划”认证企业&#xff0c;标志着飞凌嵌入式与龙芯中科的紧密型战略合作伙伴关系正式建立&#xff01; “龙芯生态伙伴计划”由龙芯中科主导发起&#xff0c;旨在推动龙芯生态企业基于龙芯平台开发产品&#xff0c;丰富龙芯…

MyBatisPlus属性自动填充和乐观锁插件+查询删除操作+整合SpringBoot出现问题解决

属性字段自动填充 一、实体类和数据表添加两个字段&#xff08;属性&#xff09; 表&#xff1a;create_tiem/update_time 实体类&#xff1a;createTime/updateTime 二、实体类中属性进行注解添加 TableField(fillFieldFill.INSERT) private Date createTime;TableField(f…

DC2DC电源设计注意事项--1,Feedback

电源采集图如下图 Feedback 采集电压点应该在靠近负载侧。这样可以减少大电流导线导致的电压差&#xff0c;真实反应输出电压值 FB_1P21采集电路靠近芯片侧&#xff0c; 2.1&#xff0c;采集分压电路上侧为Vout Vnoise, 那么一分压就噪声就小了。假如采集电路远离芯片侧&…

简洁多媒体影音库 Emby 中文最新 for mac

Emby是一款用于媒体服务器和媒体中心的软件平台。它允许用户将个人的音乐、电影、电视节目、照片和其他媒体文件组织和管理起来&#xff0c;并通过各种设备进行访问和流媒体播放。 以下是Emby可能提供的一些主要功能和特点&#xff1a; 媒体管理和组织&#xff1a;Emby允许用户…

蒙特卡洛方法的简单应用

蒙特卡洛方法的简单应用 圆周率估算 eastimate pi python version 3.11 RNG:np.random.random import os figure_save_path "file_fig" import warnings warnings.filterwarnings("error") import numpy as np np.random.seed(0) import matplotlib.pyp…

温度在线检测技术在电力电缆线路的应用

在电力电缆的日常运行检测中&#xff0c;针对电缆温度的状况&#xff0c;所采用的电力温度在线检测技术也得到了大范围的普及。电网系统中&#xff0c;其单位时间内可输送的电力能源受到其温度的变化影响。因此&#xff0c;采用更有效的方式实时检测电缆系统运行温度&#xff0…

虾皮商品链接获取虾皮商品详情数据(用 Python实现虾皮商品信息抓取)

在网页抓取方面&#xff0c;可以使用 Python、Java 等编程语言编写程序&#xff0c;通过模拟 HTTP 请求&#xff0c;获取虾皮网站上的商品页面。在数据提取方面&#xff0c;可以使用正则表达式、XPath 等方式从 HTML 代码中提取出有用的信息。值得注意的是&#xff0c;虾皮网站…

miRNA测序数据生信分析——第三讲,已知物种的生信分析实例

miRNA测序数据生信分析——第三讲&#xff0c;已知物种的生信分析实例 miRNA测序数据生信分析——第三讲&#xff0c;已知物种的生信分析实例1. 下载测序数据2. 原始数据质控——软件fastqc3. 注释tRNA和rRNA&#xff0c;使用Rfam数据库——软件blast&#xff0c;Rfam_statisti…

MySQL数据库技术笔记(3)

概述 学习MySQL数据库技术其实只需要安装mysql服务器就可以使用了。只不过对于初学者来说直接操作dos窗口方式比较麻烦&#xff0c;命令不熟悉&#xff0c;导致经常写错。在真实的开发当中直接操作dos窗口效率比较慢&#xff0c;企业中也会经常使用一些mysql数据库支持的可视化…