接了一个2000块的小活,大家进来看看值不值,附源码
如题,上周的一天,朋友圈的一个旧友找到了我,说让我帮他开发一个小工具,虽然活不大,但没个几年的全栈经验还不一定能接下来,因为麻雀虽小,涉及的内容可不少:
-
需求分析
-
原型设计
- 详细设计
-
架构选型
-
接口设计
-
数据库设计
-
-
后端开发
-
前端开发
-
服务器购买
-
服务器配置
-
镜像构建
-
服务调试
-
服务部署测试
-
优化迭代
-
交付收款
如果你对上述流程感兴趣,可以继续看下去,关注公&号:新质程序猿,回复:api-mark 可以获取源码包。
废话不多说,开整吧!
需求分析
用户故事如下,我大概评估了一下需要 1-2 个工作日,就要个 2000 块吧。
总结一下就是:
-
支持批量上传(添加)一批接口数据
-
提供获取接口,每次获取一条数据以供他自己的使用
-
提供标记接口,他使用完会标记这条数据的状态(1成功,2老号,3异常)
-
提供删除接口(多条件)
-
支持查询导出(多条件)
数据格式大概是这样的:
61057944----http://xxx/api/getcode?token=e49debc93
61057945----http://xxx/api/getcode?token=e49deb333
原型设计
看起来好像蛮简单哈~~,我随即画了一个 原型图 给他。
得到确认后,就开整吧。
注:原型设计采用的是 Axure RP 9 + ElementUI,如有需要也可以公&号留言。
详细设计
需求分析只是大概对需求进行了梳理,在进行开发之前,还需要进行深入详细的设计才能评估出工作量。
我们来拆解一下这个项目。
架构选型
首先要明确项目各关键点所采用的架构选型,如服务器怎么选,前后端框架怎么选,如何部署,安全标准,性能要求等等,这些都会影响到架构选型。
对于这个项目来说,单机足够,没啥安全要求,一句话就是够简单,无压力开整。
-
服务器:centos 7.9 4c8g 200g 足够
-
数据库:mysql 5.7+(部署使用的 mysql 8)
-
后端:springboot + jpa 够用
-
前端:vue + vue-admin-template 快速开发框架
-
部署:docker + docker-compose 方便快捷
接口设计
本项目主要涉及数据的导入,查询,导出,删除,取接口,还有非必要的登录等。
下面的接口是最终完结版涉及的接口,只有真正去开发的时候你才能明确的知道全部的需求。
-
登录接口,hard code 一段用户验证接口即可,够用
-
用户信息接口,主要懒得改 vue-admin-template 中的代码,用到了,就随便提供一个给前端吧
-
登出接口,同上,可有可无,前端用到了,随便提供一下
-
资源添加接口,重点,用户需要上传txt,嫌麻烦,让他贴文本到 textarea 框更好实现,避免了文件上传接口(虽然也不复杂)
-
接口获取接口,重点,每次取一条已添加的资源
-
单条删除接口,每次删 1 条记录
-
批量删除接口,页面提供了勾选删除操作,原本是分别调上面的单条删除,觉得不够优雅,额外增开
-
查询接口,分页返回,支持多条件:状态,日期范围,编号
-
查询导出接口,根据条件直接导出 csv 文件,没有用 excel 因为觉得复杂,csv 直接字符串拼接,也能达到 excel 的效果
-
条件删除,根据查询条件,批量删除数据
-
接口标记,对单条记录进行状态标记
你看,虽然用户故事可能就一句话,但实际开发过程中涉及到的接口及逻辑可还真不少,单查询接口就需要不少工作量的。
数据库设计
直接采用 mysql, 一张 api 表搞定:
-
id, bigint,自增
-
sn, varchar(100), 编号
-
api, varchar(1024), 接口地址
- status, int, 状态
-
-1,初始状态
-
0,已取号
-
1,成功
-
2,老号
-
3,异常
-
-
create_time, datetime 添加时间
-
update_time, datetime 更新时间
详细 SQL 语句可以从源码中获取(开头有获取方式)。
后端开发
由于内容不复杂,性能及安全性要求都不太高,所以 springboot + jpa 整起来。
通过 idea 或者如下网站快速构建一个模版项目:
https://start.aliyun.com/
额外加了几个常用的工具库:
-
lombok, 偷懒神器,免写 getter, setter 方法
-
commos-lang3,提供 StringUtils, NumberUtils 之类的工具类
-
jpa-spec, 方便构建复杂的查询语句,例如 eq, between 之类的
前端开发
前端直接用 PanJiaChen 大佬的快速开发脚手架(虽然很久没更新了,够用就好)
https://github.com/PanJiaChen/vue-admin-template
# clone the project
git clone https://github.com/PanJiaChen/vue-admin-template.git# enter the project directory
cd vue-admin-template# install dependency
npm install# develop
npm run dev
注:node 版本不能太高,我测试了 node v16 没问题,太高会报错,构建失败。推荐我之前的一篇文章,可以帮助你快速切换 node 版本:
版本不兼容,构建又失败了?NodeJS开发环境搭建,看这一篇就够了,多版本管理就是丝滑_node10 构建不成功-CSDN博客
大家直接看源码吧,被我删减了不需要的东西,变得更精简了,就 3 个页面:
-
登录页面,其实也可有可无
-
添加页面,资源添加,就一个 textarea 表单提交,加了一些格式校验及表单参数构建
-
列表页面,条件查询,选中删除,单项删除,条件导出,分页
服务器购买
服务器购买,找一个国外的 vps 就可以了,避免大陆需要备案的琐事,我这里不广告了,如有需要可以通过公*号:新质程序猿,找到我,可以告诉你。
反正不是我出钱,就随便选一个 8c4g 25Mbps 180G 的吧,280/月 对老板来说不再话下,哈哈。
服务器配置
服务器安装的是 centos 7.9 版本,因为用的比较多的缘故,大家根据喜好来即可,都一样,因为我的目标是 容器 部署,所以操作系统其实无所谓,只要能安装 docker & docker-compose 即可。
主要对系统进行了一些必要的操作:
-
内核参数优化,调整ulimit, 文件句柄之类的,从别处抄的,大家注意甄别
-
安装docker,通过 aliyun mirror 安装比较快一点
-
配置时区,调成中国上海时区
-
磁盘格式化及挂载,系统盘比较小,180G 的磁盘需要自己格式化,自己挂载,搜一搜就好了
系统优化
附上操作脚本:
# 更新源
yum makecache
# 调整时区
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
echo "Asia/Shanghai" > /etc/timezone
# 更改内核参数
cat << EOF > /etc/sysctl.d/custom.conf
net.core.somaxconn = 32768
net.core.netdev_max_backlog = 32768
net.ipv4.ip_local_port_range = 10000 65535
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_max_tw_buckets = 30000
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_fack = 1
vm.swappiness = 0
vm.overcommit_memory = 1
fs.nr_open = 1000000
fs.file-max = 2000000
kernel.core_uses_pid = 1
kernel.pid_max = 4194304
EOFsysctl -p /etc/sysctl.d/custom.confulimit -n 1000000cat << EOF >> /etc/security/limits.conf
* soft nproc 1000000
* hard nproc 1000000
* soft nofile 1000000
* hard nofile 1000000
EOF
格式化磁盘
由于系统挂载了一块独立的数据磁盘,需要自行格式化挂载,这当然不在话下
fdisk /dev/sdb
n,p,w
mkfs.xfs /dev/sdb1
mkdir -p /data
mount /dev/sdb1 /data# 查看分区ID https://zhuanlan.zhihu.com/p/62459117
blkid
# 配置开机自动挂载
vi /etc/fstab
UUID=da60a5fc-d38d-4775-a780-c6b5e0bf2956 /data xfs defaults 0 0
UUID= /data xfs defaults 0 0
UUID=13d2692c-b992-4f00-b070-26d90911610e /data xfs defaults 0 0
docker 安装
通过阿里云镜像站进行 docker-ce 安装
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
yum makecache fast
yum -y install docker-ce
#
vi /etc/docker/daemon.json
{"data-root": "/data/docker"
}
vim /usr/lib/systemd/system/docker.service
vim /usr/lib/systemd/system/containerd.service# 需配置 infinity 为 65535 ,小于系统文件句柄
LimitNOFILE=65535systemctl daemon-reloadsystemctl restart docker
systemctl enable dockersystemctl restart containerd
systemctl enable containerd# 安装 docker-compose
curl -SL https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-linux-x86_64 -o /usr/bin/docker-compose
chmod a+x /usr/bin/docker-compose
镜像构建
为了便于调试和部署,选择使用当前流行的容器进行部署,构建镜像相当比较简单,项目路径下均有对应的 Dockerfile 文件,因为我 mac 上安装的 有 docker-desktop 所以直接本地安装和 build 即可,构建完成,推到了我自己的 hub 账号下,大家也可以直接体验。
https://hub.docker.com/r/chinaxiang/laiju-web
https://hub.docker.com/r/chinaxiang/laiju-api
构建前端项目
# 构建前端项目 prod 环境
npm run build:prod
# 构建 docker image
docker build -t chinaxiang/laiju-web:v1.0 .
# 推送至个人账号(需要提前登录,这一步大家可以忽略)
docker push chinaxiang/laiju-web:v1.0
构建后端项目
# 编译构建
mvn clean package
# 构建 image
docker build -t chinaxiang/laiju-api:v1.0 .
# 推送
docker push chinaxiang/laiju-api:v1.0仓库地址:
服务调试
本地调试应该对大家来说比较熟悉了,后端直接在 idea 里启动,或者使用 java -jar 将打好的包启动起来就可以,后端接口调试的话,直接使用浏览器或者 postman, postwoman(hoppscotch) ,或者 curl 都可以。
唯一一点是,默认的 vue-admin-template 采用的 mockserver ,所以为了直接使用本地的 server api 调整了一下 devServer 配置项。
vue.conf.js 配置 proxy
....devServer: {port: port,open: true,overlay: {warnings: false,errors: true},proxy: {'/api': {target: 'http://localhost:8082',changeOrigin: true}},//before: require('./mock/mock-server.js')},
....
main.js 注释掉 mock 部分代码
....
/*** If you don't want to use mock-server* you want to use MockJs for mock api* you can execute: mockXHR()** Currently MockJs will be used in the production environment,* please remove it before going online ! ! !*/
// if (process.env.NODE_ENV === 'production') {
// const { mockXHR } = require('../mock')
// mockXHR()
// }
....
服务部署
因为安装有 docker, docker-compose 所以部署起来相对比较简单,直接一个 docker-compose.yml 文件拉起来就可以了。
services:laijuweb:image: chinaxiang/laiju-web:v1.2restart: alwaysports:- 3000:80laijuserver:image: chinaxiang/laiju-api:v1.2restart: alwaysenvironment:PROFILE: proddepends_on:- laijudblaijudb:image: mysql:8.4command:- --character-set-server=utf8mb4,- --collation-server=utf8mb4_unicode_cirestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: rootMYSQL_USER: pandaMYSQL_PASSWORD: Admin250@volumes:- ./mysql:/var/lib/mysql- ./init.sql:/docker-entrypoint-initdb.d/init.sql
init.sql
create database if not exists laiju;
use laiju;create table if not exists api
(id bigint auto_increment primary key,sn varchar(100) null,api varchar(1024) null,status int null,create_time datetime null,update_time datetime null
);grant all on *.* to panda@'%';
flush privileges;
# 启动各服务
docker-compose up -d
不过在真正部署的时候还是遇到了一些小问题,这里稍微提一下。
-
本地使用的 mysql 5.7 部署选择的 mysql 8, 配置上存在差异,调整了好一阵才 ok,详情见项目配置
-
采用 compose 部署最开始没有配置依赖关系,导致 api 启动时数据库还没启动,添加了依赖配置
部署ok后,就上线使用吧。
优化迭代
任何系统都免不了优化迭代,主要优化调整了如下几项,不过不算大改动。
前端优化
-
分页优化,查询条件改变,要把页码重置
-
删除最开始直接删除了,有点暴力,加上 confirm 确认框
-
删除非第一页最后一个选项时,页码减一,提升交互体验
-
选中删除最开始是按多个单条删除处理的,体验不好,整合到一个接口
-
status 状态显示调整为 filter 形式
-
新增了 已标记 状态过滤,包含复合条件(1新号,2老号,3异常)
-
时间范围查询条件直接转换为时间戳进行传参
后端优化
-
配合前端的复杂查询做必要的调整
-
加了必要的参数校验,避免脏数据
-
取号接口直接采用同步关键字加锁,确保并发情况下不会取到相同的号
交付使用
经测试没问题之后,找老板要钱吧,因为是熟人,所以提前报了价,没有先付钱,如果大家在接项目的时候,最好能有个定金意识,避免干活拿不到钱的情况,一般采用付一半或者4-4-2的比例。
OK,至此 2000 块到手。
你觉得这个项目收 2000 块贵吗?欢迎留言讨论交流!
如需要源码,可以关注公&号:新质程序猿,回复:api-mark 获取项目源码哟,无套路,纯粹为了增加个人气,况且,说不定哪天分享的内容会帮助到你呢!
欢迎大家批评指正,一起加油。
相关文章:

接了一个2000块的小活,大家进来看看值不值,附源码
如题,上周的一天,朋友圈的一个旧友找到了我,说让我帮他开发一个小工具,虽然活不大,但没个几年的全栈经验还不一定能接下来,因为麻雀虽小,涉及的内容可不少: 需求分析 原型设计 详细…...

基于MindFormers实现GPT2模型的推理
前言 针对MindFormers的安装,可参考本专栏里的另一篇博客 安装MindFormers(昇腾910)-CSDN博客 pipeline方式 from mindformers import pipeline from mindformers import GPT2LMHeadModel, GPT2Config, GPT2Tokenizer tok GPT2Tokenizer…...

探索腾讯云AI代码助手:智能编程的新时代
智能编程的新时代 前言开发环境介绍腾讯云 AI 代码助手使用实例生成文档解释代码生成测试修复代码人工智能技术对话 智能编程获得的帮助与提升对腾讯云AI代码助手的建议结语 前言 hello,大家好我是恒川,今天我来给大家安利一款非常好用的AI 代码助手&…...
MySQL 之 MHA 高可用架构详解
这个是在内部分享做的一个 Keynote 动画,用来演示 MHA 高可用架构及发生故障时的 Failover。动画如下: 数据库相关分享之 MySQL 的 MHA 架构详解 引言 MySQL 数据库在企业和应用中扮演着举足轻重的角色,其稳定性和可靠性对于业务的连续运行至…...

WangEditor自定义新元素,并解决自定义元素中换行无法消除样式的问题
一、背景概述 项目有自定义样式模板的需求,WangEditor没有。若直接把样式的html插入WangEditor中,无法解析,且会被自动过滤。因此,需要基于WangEditor提供的API进行二次开发。 例如,需要新增以下样式: 该…...
VBA Excel口算题
口算题函数 利用随机数写个20以内加减法口算题函数 Function Kousuan()Dim intOne As IntegerDim intTwo As IntegerDim strFlg As StringDim intFlg As IntegerDim strRtn As StringintFlg Application.WorksheetFunction.RandBetween(0, 1)strFlg "-"If intFlg…...
C++理解临时对象的来源
当程序员之间进行交谈时,他们经常把仅仅需要一小段时间的变量称为临时变量。例如在下面这段swap(交换)例程里: template<class T> void swap(T& object1, T& object2) { T temp object1; object1 object2; object2 temp; } 通常把t…...
C++协助完成返回值优化
一个返回对象的函数很难有较高的效率,因为传值返回会导致调用对象内的构造和析构函数(参见条款M19),这种调用是不能避免的。问题很简单:一个函数要么为了保证正确的行为而返回对象要么就不这么做。如果它返回了对象,就没有办法摆脱…...
2024年睿抗机器人开发者大赛(RAICOM)国赛题解
目录 RC-u1 大家一起查作弊 分数 15 RC-u2 谁进线下了?II 分数 20 RC-u3 势均力敌 分数 25 RC-u4 City 不 City 分数 30 RC-u5 贪心消消乐 分数 30 RC-u1 大家一起查作弊 分数 15 简单模拟题,对于多行读入使用while(getline(cin…...

声明式UI语法
一、ArkTS的基本组成 Entry // 装饰器 Component // 装饰器 struct Hello { // 自定义组件State myText: string World;build() { // UI描述Column() { // 系统组件Text(Hello ${this.myText}).fontSize(50)Divider()Button(Click me).onClick(() > { // 事件方法t…...
JDBC连接数和1521连接数之间的区别和联系(Java Database Connectivity)
JDBC(Java Database Connectivity)连接数和1521连接数之间的区别和联系如下: 区别 概念不同: JDBC连接数:指通过JDBC技术建立的数据库连接数。JDBC是Java中的一套API,用于连接和操作关系数据库。JDBC连接数…...

Leetcode - 136双周赛
目录 一,3238. 求出胜利玩家的数目 二,3239. 最少翻转次数使二进制矩阵回文 I 三,3240. 最少翻转次数使二进制矩阵回文 II 四,3241. 标记所有节点需要的时间 一,3238. 求出胜利玩家的数目 本题直接暴力求解&#x…...
SQLite ORDER BY 语句
SQLite ORDER BY 语句 SQLite 的 ORDER BY 语句用于对查询结果进行排序。排序可以是升序(ASC)或降序(DESC)。默认情况下,如果不指定排序方式,ORDER BY 会以升序对结果进行排序。 语法 SQLite ORDER BY 语…...
MTK Android12 系统中应用加载 .so 文件的问题分析
在本篇博客中,我将详细总结在 Android 12 系统上进行的几个实验,包括如何加载自定义 JAR 文件、如何解压和确认 .so 文件,以及如何验证系统报错提示。本文将介绍使用 PathClassLoader 和 DexClassLoader 动态加载类的实验,分析系统报错信息,并最终得出结论。 推荐:《Andr…...

bpmn简单使用(制作流程图)
1、先下载依赖,下面是我下载的版本 "bpmn-io/properties-panel": "^3.23.0", "bpmn-js": "^17.9.1", "bpmn-js-properties-panel": "^5.6.1", "camunda-bpmn-moddle": "^7.0.1",…...
【算法模板】算竞技巧:Python对拍数据生成
在计算机编程竞赛中,对拍(Testlib)是一种验证程序正确性的方法。它通常用于检查一个程序的输出是否与另一个程序的输出一致,以确保程序的正确性。 对拍程序 【算法模板】算竞技巧:对拍全解_算法竞赛对拍-CSDN博客 #i…...

计算机基本理论与程序运行原理概述
目录 计算机的基本表示方法 计算机的组成 程序运行的原理 指令执行的流水线 编译原理 个人理解 面试题总结 计算机的基本表示方法 计算机系统使用高、低电平来表示逻辑1和0。数据在计算机中的存储、传输和处理均以二进制形式进行。数据通过总线作为电信号进行传输&…...

SpringBoot中的server.context-path
目录 一、问题引入 二、代码片段展示 2.1.接口层 2.2.application.properties 三、问题分析 3.1.server.context-path 作用 3.2.正确展示 四、HTTP请求响应码简介 4.1.响应码参考来源 4.2.源码示例 4.2.1.源码总述 4.2.2.正常情况——2XX: generally "OK&…...

AI绘画绘画 Stable Diffusion ,从零开始轻松变现,AI绘画副业创收指南,一天一个AI帮你赚钱小技巧!
大家好,我是灵魂画师向阳 通过长达几个月的AI绘画Stable Diffusion 系统教程,相信大家已经对AI绘画有了一个大概的认知。最近就有很多粉丝总是问我,AI绘画学会后如何进行变现,或者是做副业呢? 那今天我就分享一些目前…...

阿里云镜像站,提供了各种第三方镜像地址
阿里云提供了各项镜像缓存地址,对于很多国外服务的地址,通过阿里云缓存的地址去下载,速度会非常快。 如下,打开阿里云官方网站: 进入“镜像站”,如下图所示: 有我们常用的 npm、maven、操作系统…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...