1. 项目概述
作为一名有多年Java开发经验的程序员,我最近完成了一个基于Spring Boot的个人记账系统。这个项目不仅涵盖了完整的开发流程,还包含了详细的文档说明和源码解析,非常适合作为Java毕业设计或课程设计的参考案例。
个人记账系统是现代生活中非常实用的工具,它能帮助用户记录日常收支情况,分析消费习惯,实现财务管理的数字化和智能化。在开发过程中,我采用了当前主流的Spring Boot+Vue前后端分离架构,结合MySQL数据库,实现了完整的CRUD功能和用户权限管理。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 技术选型分析
在项目初期,我经过仔细的技术选型评估,最终确定了以下技术栈:
后端技术:
- Spring Boot 2.7.x:简化了Spring应用的初始搭建和开发过程
- MyBatis-Plus 3.5.x:强大的ORM框架,提供了丰富的CRUD接口
- Shiro 1.10.x:负责系统的认证和授权功能
- Lombok 1.18.x:简化Java Bean的编写
前端技术:
- Vue.js 3.x:渐进式JavaScript框架
- Element Plus:基于Vue 3的组件库
- Axios:处理HTTP请求
- ECharts:数据可视化图表展示
数据库:
- MySQL 8.0:关系型数据库
- Redis 6.x:缓存和会话管理
选择这些技术主要基于以下考虑:
- Spring Boot的自动配置和约定优于配置原则大大提高了开发效率
- Vue.js的响应式特性和组件化开发非常适合构建交互式用户界面
- MySQL作为成熟的关系型数据库,在数据一致性和事务处理方面表现优异
- MyBatis-Plus在MyBatis基础上提供了更多便捷功能,减少了大量样板代码
2.2 系统架构模式
系统采用经典的MVC(Model-View-Controller)架构模式,结合前后端分离的设计思想:
模型层(Model):
- 实体类:对应数据库表结构
- DAO层:数据访问接口,使用MyBatis-Plus实现
- Service层:业务逻辑处理
- DTO:数据传输对象
视图层(View):
- 前端Vue组件
- 页面模板
- 静态资源
控制层(Controller):
- RESTful API接口
- 请求参数验证
- 响应数据封装
这种分层架构使得系统各组件职责明确,耦合度低,便于维护和扩展。前后端通过JSON格式数据进行交互,前端负责页面渲染和用户交互,后端专注于业务逻辑处理和数据持久化。
3. 数据库设计
3.1 数据库表结构
系统主要包含以下几张核心表:
- 用户表(user)
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
`salt` varchar(20) DEFAULT NULL COMMENT '盐值',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像',
`status` tinyint DEFAULT '1' COMMENT '状态:0-禁用,1-正常',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
- 账目表(account)
sql复制CREATE TABLE `account` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '账目ID',
`user_id` bigint NOT NULL COMMENT '用户ID',
`type` tinyint NOT NULL COMMENT '类型:1-收入,2-支出',
`category_id` bigint NOT NULL COMMENT '分类ID',
`amount` decimal(10,2) NOT NULL COMMENT '金额',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`record_date` date NOT NULL COMMENT '记录日期',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_record_date` (`record_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账目表';
- 分类表(category)
sql复制CREATE TABLE `category` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类ID',
`user_id` bigint DEFAULT NULL COMMENT '用户ID(NULL表示系统默认分类)',
`name` varchar(50) NOT NULL COMMENT '分类名称',
`type` tinyint NOT NULL COMMENT '类型:1-收入,2-支出',
`icon` varchar(100) DEFAULT NULL COMMENT '图标',
`sort` int DEFAULT '0' COMMENT '排序',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分类表';
3.2 数据库设计原则
在设计数据库时,我遵循了以下原则:
- 三范式设计:确保数据冗余最小化,避免更新异常
- 适当的反范式:在查询性能关键路径上适当增加冗余,如记录日期单独存储
- 索引优化:为常用查询条件创建合适的索引
- 字段类型选择:根据实际需求选择最合适的类型,如金额使用DECIMAL
- 命名规范:表名和字段名使用下划线命名法,保持一致性
4. 核心功能实现
4.1 用户认证与授权
系统采用Shiro框架实现用户认证和权限控制。主要实现步骤:
- 配置Shiro
java复制@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
// 设置登录页面
factoryBean.setLoginUrl("/login");
// 设置未授权页面
factoryBean.setUnauthorizedUrl("/unauthorized");
// 配置拦截规则
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/api/auth/**", "anon"); // 认证相关接口放行
filterMap.put("/api/**", "authc"); // 其他API需要认证
factoryBean.setFilterChainDefinitionMap(filterMap);
return factoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager(Realm realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
@Bean
public Realm realm() {
return new AccountRealm();
}
}
- 自定义Realm
java复制public class AccountRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取当前用户
User user = (User) principals.getPrimaryPrincipal();
// 查询用户角色和权限
Set<String> roles = userService.getUserRoles(user.getId());
Set<String> permissions = userService.getUserPermissions(user.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.setStringPermissions(permissions);
return in
