记账这件事,说大不大说小不小。我见过太多小老板用Excel记流水账,月底对账时发现分类混乱;也见过不少自由职业者用纸质本子记账,年底报税时翻箱倒柜找单据。这个基于SpringBoot的轻量化记账系统,就是为解决这类痛点而生。
与传统财务软件不同,我们定位非常明确:面向个人用户和20人以下小微团队。不需要复杂的ERP功能,核心解决三个问题:①日常收支快速记录 ②多维度统计可视化 ③税务相关数据导出。实测表明,90%的个体经营者每月交易记录不超过300笔,这个量级用全功能财务软件就像用高射炮打蚊子。
轻量化不等于简陋。SpringBoot的starter机制让我们能按需引入模块:
spring-boot-starter-web 处理HTTP请求spring-boot-starter-data-jpa 实现ORMspring-boot-starter-thymeleaf 服务端渲染spring-boot-starter-security 基础权限控制对比传统SSM架构,启动时间从8秒缩短到1.5秒(实测数据),内存占用减少40%。这对可能部署在低配云服务器的小微用户至关重要。
采用MySQL 8.0+(支持窗口函数),核心表仅5张:
sql复制CREATE TABLE `t_transaction` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`user_id` BIGINT NOT NULL,
`amount` DECIMAL(12,2) NOT NULL COMMENT '支持负数为支出',
`category_id` INT COMMENT '关联分类表',
`transaction_time` DATETIME NOT NULL,
`remark` VARCHAR(200) DEFAULT '',
`attachment_url` VARCHAR(500) DEFAULT '' COMMENT '凭证图片OSS地址'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别注意:
传统记账软件的通病是操作路径深。我们实现两种快捷录入方式:
方式一:命令行式输入
code复制/记 餐饮 42.5 #晚餐兰州拉面
后端通过正则提取关键信息:
java复制Pattern pattern = Pattern.compile("/记\\s(\\S+)\\s(\\d+\\.?\\d*)");
Matcher matcher = pattern.matcher(input);
if(matcher.find()){
String category = matcher.group(1);
BigDecimal amount = new BigDecimal(matcher.group(2));
}
方式二:语音输入转译
接入百度语音识别API,处理流程:
code复制录音 → 转文字 → NLP提取金额/分类 → 人工校验
实测普通话准确率可达92%,方言支持需定制。
很多用户记账时不填分类,我们实现自动归类:
核心代码片段:
java复制public Category predictCategory(String remark, Long userId) {
List<KeywordWeight> keywords = jpa.query(
"SELECT content, category_id, COUNT(*) as freq " +
"FROM t_transaction " +
"WHERE user_id = ?1 AND remark LIKE CONCAT('%',?2,'%') " +
"GROUP BY content, category_id",
userId, remark);
return keywords.stream()
.max(Comparator.comparingDouble(kw -> kw.freq * kw.tfidf))
.map(kw -> categoryRepo.findById(kw.categoryId))
.orElse(null);
}
采用ECharts实现交互式图表,关键技术点:
java复制@GetMapping("/stats/{type}")
public StatsResult getStats(
@PathVariable String type,
@RequestParam LocalDate start,
@RequestParam LocalDate end) {
return switch (type) {
case "daily" -> statsService.getDailyFlow(start, end);
case "category" -> statsService.getCategoryPie(start, end);
default -> throw new IllegalArgumentException();
};
}
针对个体户的报税需求,实现:
关键代码:
java复制public void exportTaxReport(Long userId, OutputStream out) {
List<Transaction> transactions = transactionRepo.findByUserAndTimeRange(...);
try (ExcelWriter writer = ExcelUtil.getWriter(out)) {
writer.addHeaderAlias("month", "月份");
writer.addHeaderAlias("income", "应税收入");
// ...其他列映射
writer.write(transactions, true);
}
}
针对不同用户群体提供三种部署方式:
| 部署方式 | 适用场景 | 硬件要求 | 启动命令 |
|---|---|---|---|
| 单机JAR包 | 个人使用 | 1核1G | java -jar account.jar |
| Docker容器 | 小微团队 | 2核2G | docker-compose up -d |
| 云托管平台 | 无技术能力用户 | 无需维护 | 提供SaaS访问链接 |
使用JMeter模拟并发记账操作(100用户持续30分钟):
| 指标 | 单机部署 | Docker部署 | 结果分析 |
|---|---|---|---|
| 平均响应时间 | 128ms | 152ms | 满足高频操作需求 |
| 错误率 | 0.12% | 0.09% | 主要来自重复提交 |
| 内存占用峰值 | 512MB | 680MB | 建议Docker分配1G以上内存 |
根据实际项目经验,客户常要求:
accountBookId字段,修改所有DAO查询条件ALTER TABLE ... ADD COLUMN,勿修改原字段定义/api/v1/与/api/v2/并存重要提示:所有定制必须通过
application-custom.yml覆盖配置,严禁直接修改主配置!
完整交付包包含:
code复制/docs
├── 需求规格说明书.md
├── 数据库设计.pdf
├── API文档.html
/src
├── main
│ ├── java # 后端源码
│ └── resources
│ ├── static # 前端构建产物
│ └── templates
└── test # 单元测试
/deploy
├── docker-compose.yml
└── init.sql # 数据库初始化脚本
坑1:时区问题导致统计偏差
现象:每日统计在UTC时间8:00分界
解决:
java复制spring.jpa.properties.hibernate.jdbc.time_zone=Asia/Shanghai
spring.datasource.url=jdbc:mysql://...?serverTimezone=Asia/Shanghai
坑2:金额计算精度丢失
错误做法:
java复制double total = 0.1 + 0.2; // 得到0.30000000000000004
正确做法:
java复制BigDecimal total = new BigDecimal("0.1").add(new BigDecimal("0.2"));
坑3:分类缓存雪崩
解决方案:双重检查锁 + 短期缓存
java复制public List<Category> getUserCategories(Long userId) {
String cacheKey = "user_categories:" + userId;
List<Category> cached = redisTemplate.opsForValue().get(cacheKey);
if (cached != null) return cached;
synchronized (this) {
cached = redisTemplate.opsForValue().get(cacheKey);
if (cached == null) {
cached = categoryRepo.findByUserId(userId);
redisTemplate.opsForValue().set(
cacheKey,
cached,
5, TimeUnit.MINUTES); // 短时间缓存
}
}
return cached;
}
这个项目最让我意外的收获是:很多技术难点其实不在代码层面,而在于如何用最小成本满足非技术用户的真实需求。比如我们花了三周时间优化分类预测算法,最后发现用户更在意的是能不能快速修正错误分类——于是增加了"长按拖动到正确分类"的功能,问题迎刃而解。