1. 项目背景与核心价值
在数字化浪潮席卷各行各业的今天,家庭财务管理正经历着从传统纸质账本到智能化系统的转型。作为一名长期深耕Java企业级开发的工程师,我发现许多家庭仍在用Excel表格或手机备忘录记录收支,这种方式存在数据易丢失、统计不直观、多成员协作困难等痛点。基于BS架构的家庭理财管理系统正是为解决这些问题而生。
这个采用SSM(Spring+SpringMVC+MyBatis)框架的Java项目,具有典型的Web应用三层架构特征:
- 前端采用Bootstrap+jQuery实现响应式布局
- 后端基于Spring的IoC容器管理业务组件
- 数据持久层通过MyBatis实现ORM映射
提示:选择SSM而非SpringBoot的考虑在于教学目的——SSM需要手动配置各个组件,更利于理解框架底层协作机制,这对Java学习者尤为重要。
系统核心价值体现在三个维度:
- 多终端适配:BS架构使系统可通过浏览器直接访问,无需安装客户端,手机/电脑/平板均可使用
- 财务可视化:通过ECharts实现收支趋势图、消费占比饼图等数据可视化呈现
- 协作共享:支持家庭成员账号体系,实现共同记账、预算监督等协作场景
2. 技术架构解析
2.1 整体架构设计
系统采用经典MVC模式分层实现,各层技术选型如下表所示:
| 层级 | 技术组件 | 版本 | 核心职责 |
|---|---|---|---|
| 表现层 | JSP+JSTL | 2.3 | 视图渲染、表单验证 |
| 控制层 | SpringMVC | 5.3.18 | 请求路由、参数绑定 |
| 业务层 | Spring | 5.3.18 | 事务管理、服务组装 |
| 持久层 | MyBatis | 3.5.9 | SQL映射、缓存管理 |
| 数据库 | MySQL | 8.0.28 | 数据存储 |
2.2 关键配置实现
在IDEA中创建Maven项目后,需要特别注意几个核心配置文件的编写:
数据库连接池配置(applicationContext.xml)
xml复制<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/family_finance?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<!-- 连接池参数优化 -->
<property name="initialSize" value="5"/>
<property name="maxActive" value="20"/>
</bean>
MyBatis映射器扫描(spring-mybatis.xml)
xml复制<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.finance.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
注意:Druid连接池相比默认的HikariCP提供了更完善的管理界面,适合需要监控SQL性能的场景。
3. 核心功能实现细节
3.1 收支记录模块
作为系统的核心功能,收支记录采用AJAX异步提交方案提升用户体验。前端表单通过jQuery Validation进行实时校验:
javascript复制$("#recordForm").validate({
rules: {
amount: {
required: true,
number: true,
min: 0.01
},
category: "required"
},
submitHandler: function(form) {
$.post("record/add", $(form).serialize(), function(data){
if(data.success) {
refreshRecordList();
$("#recordModal").modal('hide');
}
});
}
});
后端Controller采用RESTful风格设计:
java复制@RestController
@RequestMapping("/record")
public class RecordController {
@Autowired
private RecordService recordService;
@PostMapping("/add")
public Result addRecord(@Valid Record record, BindingResult result) {
if(result.hasErrors()) {
return Result.error(result.getFieldError().getDefaultMessage());
}
recordService.addRecord(record);
return Result.success();
}
}
3.2 数据统计模块
统计功能采用MyBatis的动态SQL实现多条件查询:
xml复制<select id="selectByCondition" resultType="RecordVO">
SELECT r.*, c.name as categoryName
FROM record r LEFT JOIN category c ON r.category_id = c.id
<where>
<if test="userId != null">AND r.user_id = #{userId}</if>
<if test="type != null">AND r.type = #{type}</if>
<if test="startDate != null">AND r.create_time >= #{startDate}</if>
<if test="endDate != null">AND r.create_time <= #{endDate}</if>
</where>
ORDER BY r.create_time DESC
</select>
ECharts的配置示例展示月度收支趋势:
javascript复制function initTrendChart(data) {
var chart = echarts.init(document.getElementById('trendChart'));
var option = {
tooltip: { trigger: 'axis' },
legend: { data:['收入','支出'] },
xAxis: { type: 'category', data: data.months },
yAxis: { type: 'value' },
series: [
{ name:'收入', type:'line', data:data.income },
{ name:'支出', type:'line', data:data.expense }
]
};
chart.setOption(option);
}
4. 开发环境搭建指南
4.1 IDEA项目配置
-
JDK配置:建议使用JDK11(LTS版本),在Project Structure中设置:
- Project SDK:Java 11
- Project language level:11
-
Maven配置:
xml复制<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> -
Tomcat部署:
- 使用Tomcat 9.x版本
- Deployment添加Artifact选择war exploded
- Context path设置为"/finance"
4.2 数据库初始化
执行以下SQL创建核心表结构:
sql复制CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
`real_name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `record` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`category_id` int NOT NULL,
`type` tinyint NOT NULL COMMENT '1-收入 2-支出',
`amount` decimal(10,2) NOT NULL,
`remark` varchar(200) DEFAULT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `category_id` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5. 典型问题解决方案
5.1 事务管理配置
在Spring配置中声明式事务管理时,容易忽略对异常类型的配置:
xml复制<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
关键点:rollback-for="Exception"确保所有异常都会触发回滚,而不仅是RuntimeException
5.2 日期处理方案
前端传递的日期字符串到后端LocalDateTime的转换:
- 添加全局转换器配置:
java复制@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
- 前端传递ISO格式日期:
javascript复制$.ajax({
url: "record/list",
data: {
startDate: moment(startDate).format("YYYY-MM-DDTHH:mm:ss")
}
});
6. 项目优化建议
6.1 性能优化措施
-
MyBatis二级缓存:在mapper.xml中添加缓存配置
xml复制<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/> -
静态资源缓存:在SpringMVC配置中添加资源映射
java复制@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/") .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)); }
6.2 安全增强方案
-
密码加密存储:采用BCryptPasswordEncoder
java复制@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } -
XSS防护:自定义HttpServletRequestWrapper
java复制public class XssRequestWrapper extends HttpServletRequestWrapper { public XssRequestWrapper(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { return HtmlUtils.htmlEscape(super.getParameter(name)); } }
7. 扩展功能思路
7.1 多账本支持
扩展数据模型实现家庭多账本管理:
java复制@Entity
public class AccountBook {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToMany
@JoinTable(name = "user_account_book",
joinColumns = @JoinColumn(name = "book_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
private Set<User> members = new HashSet<>();
}
7.2 微信小程序接入
通过Spring Security OAuth2提供API认证:
java复制@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("weapp")
.secret(passwordEncoder.encode("weapp123"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("all");
}
}
在实际开发中,我发现系统初期最容易出现的问题是日期格式处理不一致和事务配置不完整。建议在开发前期就建立统一的异常处理机制和日期处理策略,这能节省大量后期调试时间。对于家庭使用场景,可以适当简化权限控制模型,重点保证数据可视化的直观性和多设备访问的流畅性。
