Gin,Gorm实现Web计算器
目录
- 仓库链接
- 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表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 40 | 20 |
• Estimate | 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 650 | 630 |
• Analysis | 需求分析 (包括学习新技术) | 40 | 30 |
• Design Spec | 生成设计文档 | 80 | 75 |
• Design Review | 设计复审 | 35 | 45 |
• Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 25 | 20 |
• Design | 具体设计 | 35 | 30 |
• Coding | 具体编码 | 325 | 320 |
• Code Review | 代码复审 | 65 | 60 |
• Test | 测试(自我测试,修改代码,提交修改) | 60 | 50 |
Reporting | 报告 | 95 | 90 |
• Test Report | 测试报告 | 25 | 20 |
• Size Measurement | 计算工作量 | 10 | 15 |
• Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 45 | 55 |
合计 | 670 | 630 |
1. 成品展示
1.基础运算
2. 清零回退
3.错误提示
4.历史记录
拓展功能
1.前端可修改的利率计算器
2.科学计算器
3. 按钮切换不同计算器模式
4.用户在一次运算后不清零继续输入操作符,替换表达式为上次答案
2.设计实现过程
- 前端:前端需要在上一轮作业的基础上加以完善。首先要扩充为两个输入框,一个用于显示用户输入的表达式,一个用于显示答案。同时在上一轮的form基础上再做一个利率计算器(利率计算器和存款计算器可以共用一个div)。同时使用fetch向后端传发数据。
- 后端:后端使用Gin做Web框架。通过路由组和hander接前端请求。Gin相比于Hertz是一个轻量级的框架适合做这种小项目。数据库交互用Gorm。
- 数据库:只用到了Mysql。存历史记录,存款、贷款三张表。暂且把这个计算器看作单机版本,所以在存历史记录的时候没有特意区分不同用户ID。可视化工具推荐Dbeaver。
3.代码说明
- 前端采用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 = "贷款计算器"}
}
- 后端启动服务:
package mainimport ("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.Durationmoney := cal.Moneyif op == 1 {var deposit entity.Depositmysql.DB.Where("duration <= ?", duration).Order("duration desc").Limit(1).First(&deposit)return money * deposit.Rate / 100}var loans entity.Loanmysql.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代码不断增删猜测效果/询问他人。感觉前端代码实在写的不堪入目,还好最后效果感觉还行。
有些疑惑为什么要一个人完成前后端,可能全栈是学院派的宿命。
相关文章:

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

11-网络篇-DNS步骤
1.URL URL就是我们常说的网址 https://www.baidu.com/?from1086k https是协议 m.baidu.com是服务器域名 ?from1086k是路径 2.域名 比如https://www.baidu.com 顶级域名.com 二级域名baidu 三级域名www 3.域名解析DNS DNS就是将域名转换成IP的过程 根域名服务器:…...

设计师都应该知道的事:极简主义家具该怎么去用
这座房子有黑暗而沉重的特征,包括棕色和白色的马赛克浴室瓷砖,弯曲的锻铁壁灯和土黄色的威尼斯石膏墙。但由于房屋与他们的风格相去甚远,白色,干净和简约,接下来我们就着这个方向去帮助房主进行改造。 她解释说&#x…...

设计模式02———建造者模式 c#
首先我们打开一个项目 在这个初始界面我们需要做一些准备工作 建基础通用包 创建一个Plane 重置后 缩放100倍 加一个颜色 更换天空盒(个人喜好) 任务:使用【UI】点击生成6种车零件组装不同类型车 【建造者模式】 首先资源商店下载车模型 将C…...

2023最新接口自动化测试面试题
1、get和post的区别? l http是上层请求协议,主要定义了服务端和客户端的交互规格,底层都是tcp/ip协议 l Get会把参数附在url之后,用?分割,&连接不同参数,Get获取资源,post会把…...

GaN器件的工作原理
目录 AlGaN/GaNHEMT 器件工作原理(常开-耗尽型器件)常关 AlGaN/GaN 功率晶体管(增强型器件)HD-GIT与SP-HEMT AlGaN/GaNHEMT 器件工作原理(常开-耗尽型器件) 来源:毫米波GaN基功率器件及MMIC电路…...
点云从入门到精通技术详解100篇-海量三维点云的空间索引及可视化应用(续)
目录 3.2.3 方向八叉树与八叉树的比较 3.3 多级索引结构 3.3.1 多级索引结构的构建...

androidx和v4包资源冲突解决方法
一、资源包会报如下错误: 错误类似 (androidx.core:core:1.10.0) 和 (com.android.support:support-compat:24.2.0) 表示资源重复,不知调用androidx包下面的,还是v4包下面的 Duplicate class android.support.v4.app.INotificationSideCha…...

【发烧期间随笔】第一次游戏开发经历的总结与反思
一、前言 这两天三阳了,头疼头晕恶心发烧打喷嚏流鼻涕咳嗽嗓子疼气管疼都找上门来了,这导致一周以来都没学什么东西,无意间又刷到各个游戏厂关于本人目标岗位HC骤减且要求造火箭的能力的消息,这两天一直是在病痛和焦虑中度过的&a…...
CCombBox组合框
1、 MFC_Combo_Box(组合框)的详细用法_mfc combo-CSDN博客 2、 常用属性设置: 属性 含义 data 设置内容,不同内容间用英文的分号“;”分隔 type 显示风格 Sort True 内容自动排序 常用接口: 接口 功能 CComboBox::AddString 组…...

机器学习-有监督学习-神经网络
目录 线性模型分类与回归感知机模型激活函数维度诅咒过拟合和欠拟合正则数据增强数值稳定性神经网络大家族CNNRNNGNN(图神经网络)GAN 线性模型 向量版本 y ⟨ w , x ⟩ b y \langle w, x \rangle b y⟨w,x⟩b 分类与回归 懂得两者区别激活函数&a…...
React之组件通信
#一、是什么 我们将组件间通信可以拆分为两个词: 组件通信 回顾Vue系列 (opens new window)的文章,组件是vue中最强大的功能之一,同样组件化是React的核心思想 相比vue,React的组件更加灵活和多样,按照不同的方式可…...
什么是微服务架构
阅读“微服务架构”一词可能会让您直观地了解该术语的含义:计算架构中的小型服务。这个定义并不完全错误,但也不完全正确。 微服务架构通常被称为“打破整体”的一种方式。遗憾的是,这与《2001:太空漫游》无关,而是将…...
<%=%>模板写法
<%%> 这种写法通常称为 "内嵌式模板" 或 "模板标记",在前端开发中,这种标记语法用于将动态数据嵌入HTML模板中。这种写法通常与模板引擎一起使用,这些模板引擎会根据提供的数据动态生成HTML。 不同的模板引擎可能…...

python爬取boss直聘数据(selenium+xpath)
文章目录 一、主要目标二、开发环境三、selenium安装和驱动下载四、主要思路五、代码展示和说明1、导入相关库2、启动浏览器3、搜索框定位创建csv文件招聘页面数据解析(XPATH)总代码效果展示 六、总结 一、主要目标 以boss直聘为目标网站,主要目的是爬取下图中的所…...

GEO生信数据挖掘(六)实践案例——四分类结核病基因数据预处理分析
前面五节,我们使用阿尔兹海默症数据做了一个数据预处理案例,包括如下内容: GEO生信数据挖掘(一)数据集下载和初步观察 GEO生信数据挖掘(二)下载基因芯片平台文件及注释 GEO生信数据挖掘&…...
8.Mobilenetv2网络代码实现
代码如下: import math import os import numpy as npimport torch import torch.nn as nn import torch.utils.model_zoo as model_zoo#1.建立带有bn的卷积网络 def conv_bn(inp, oup, stride):return nn.Sequential(nn.Conv2d(inp,oup,3,stride,biasFalse),nn.Bat…...
Spring Boot Controller
刚入门小白,详细请看这篇SpringBoot各种Controller写法_springboot controller-CSDN博客 Spring Boot 提供了Controller和RestController两种注解。 Controller 返回一个string,其内容就是指向的html文件名称。 Controller public class HelloControll…...
在网络安全、爬虫和HTTP协议中的重要性和应用
1. Socks5代理:保障多协议安全传输 Socks5代理是一种功能强大的代理协议,支持多种网络协议,包括HTTP、HTTPS和FTP。相比之下,Socks5代理提供了更高的安全性和功能性,包括: 多协议支持: Socks5代…...

Web测试框架SeleniumBase
首先,SeleniumBase支持 pip安装: > pip install seleniumbase它依赖的库比较多,包括pytest、nose这些第三方单元测试框架,是为更方便的运行测试用例,因为这两个测试框架是支持unittest测试用例的执行的。 Seleniu…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...