1. 项目概述与背景
网咖管理系统作为现代娱乐场所的核心运营工具,其重要性不言而喻。随着互联网技术的快速发展,传统的手工登记和人工管理模式已经无法满足网咖行业的需求。这个基于SpringBoot的毕业设计项目,正是为了解决网咖日常运营中的痛点问题而设计的现代化管理系统。
我在实际开发过程中发现,一个完善的网咖管理系统需要处理以下几个核心业务场景:会员管理、上机计费、商品销售、设备维护以及数据统计分析。这些功能模块共同构成了网咖日常运营的完整闭环,而SpringBoot框架的轻量级特性和快速开发能力,使其成为实现这类管理系统的理想选择。
2. 系统架构设计
2.1 技术栈选型
本系统采用经典的三层架构设计:
- 表现层:Thymeleaf模板引擎 + Bootstrap前端框架
- 业务逻辑层:SpringBoot 2.7 + Spring Security
- 数据持久层:MyBatis-Plus + MySQL 8.0
选择这套技术栈主要基于以下考虑:
- Thymeleaf天然支持Spring生态,模板语法简单易学
- MyBatis-Plus的代码生成器和Wrapper条件构造器能极大提升开发效率
- Spring Security提供了完善的权限控制解决方案
2.2 数据库设计要点
网咖管理系统的数据库设计有几个关键表需要特别注意:
sql复制CREATE TABLE `member` (
`id` bigint NOT NULL AUTO_INCREMENT,
`card_no` varchar(20) NOT NULL COMMENT '会员卡号',
`name` varchar(50) DEFAULT NULL,
`balance` decimal(10,2) DEFAULT '0.00',
`phone` varchar(20) DEFAULT NULL,
`status` tinyint DEFAULT '1' COMMENT '1-正常 0-冻结',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_card_no` (`card_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `computer` (
`id` bigint NOT NULL AUTO_INCREMENT,
`code` varchar(20) NOT NULL COMMENT '机器编号',
`ip_address` varchar(20) DEFAULT NULL,
`status` tinyint DEFAULT '0' COMMENT '0-空闲 1-使用中 2-维护中',
`current_user` bigint DEFAULT NULL COMMENT '当前使用者ID',
`start_time` datetime DEFAULT NULL,
`last_maintain` date DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现
3.1 会员管理模块
会员系统是网咖运营的基础,我们实现了完整的CRUD功能,并特别关注以下几个关键点:
- 会员卡号生成规则:
java复制public String generateCardNo() {
// 区号(2位) + 年月(4位) + 随机数(4位)
String areaCode = "01";
String timePart = new SimpleDateFormat("yyMM").format(new Date());
String randomPart = String.format("%04d", new Random().nextInt(10000));
return areaCode + timePart + randomPart;
}
- 余额充值的事务处理:
java复制@Transactional
public Result recharge(Long memberId, BigDecimal amount) {
// 验证会员状态
Member member = memberMapper.selectById(memberId);
if(member == null || member.getStatus() == 0) {
return Result.error("会员不存在或已被冻结");
}
// 更新余额
memberMapper.updateBalance(memberId, amount);
// 记录充值流水
RechargeRecord record = new RechargeRecord();
record.setMemberId(memberId);
record.setAmount(amount);
record.setCreateTime(new Date());
rechargeRecordMapper.insert(record);
return Result.success();
}
3.2 上机计费模块
计费系统是网咖管理的核心,我们实现了以下关键功能:
- 多时段计费策略:
java复制public BigDecimal calculateFee(Date startTime, Date endTime) {
// 获取当前计费规则
BillingRule rule = ruleMapper.selectCurrentRule();
// 计算使用时长(分钟)
long duration = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
// 分段计费逻辑
if(duration <= rule.getFreeMinutes()) {
return BigDecimal.ZERO;
}
// 计算实际收费时长
long chargeMinutes = duration - rule.getFreeMinutes();
// 按小时取整
long hours = chargeMinutes / 60;
if(chargeMinutes % 60 > 0) {
hours++;
}
return rule.getPricePerHour().multiply(new BigDecimal(hours));
}
- 实时计费状态监控:
我们使用WebSocket实现了实时状态推送,前端每60秒获取一次各机器的使用状态:
java复制@GetMapping("/status")
public List<ComputerStatusVO> getComputerStatus() {
return computerService.listAll()
.stream()
.map(c -> {
ComputerStatusVO vo = new ComputerStatusVO();
vo.setComputerId(c.getId());
vo.setStatus(c.getStatus());
if(c.getStatus() == 1) {
vo.setUsedTime((System.currentTimeMillis() - c.getStartTime().getTime()) / (1000 * 60));
}
return vo;
})
.collect(Collectors.toList());
}
4. 系统安全与权限控制
4.1 基于角色的访问控制
我们使用Spring Security实现了完善的RBAC模型:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/cashier/**").hasAnyRole("CASHIER", "ADMIN")
.antMatchers("/member/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
.and()
.logout()
.permitAll();
}
}
4.2 敏感数据保护
对于会员密码等敏感信息,我们采用BCrypt加密存储:
java复制public class PasswordUtil {
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
public static String encode(String rawPassword) {
return encoder.encode(rawPassword);
}
public static boolean matches(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
5. 系统部署与优化
5.1 性能优化实践
- 缓存策略:
java复制@Service
@CacheConfig(cacheNames = "billingRules")
public class BillingRuleServiceImpl implements BillingRuleService {
@Autowired
private BillingRuleMapper ruleMapper;
@Override
@Cacheable(key = "'current'")
public BillingRule getCurrentRule() {
return ruleMapper.selectCurrentRule();
}
@Override
@CacheEvict(key = "'current'")
public void updateRule(BillingRule rule) {
ruleMapper.updateById(rule);
}
}
- 数据库连接池配置:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/netbar?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
5.2 日志监控方案
我们采用SLF4J+Logback组合,并配置了完善的日志策略:
xml复制<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/netbar.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/netbar.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
6. 开发经验与问题排查
6.1 常见问题解决方案
- 并发充值问题:
java复制@Transactional
public Result recharge(Long memberId, BigDecimal amount) {
// 使用SELECT FOR UPDATE加锁
Member member = memberMapper.selectByIdForUpdate(memberId);
if(member == null || member.getStatus() == 0) {
return Result.error("会员不存在或已被冻结");
}
// 更新余额
member.setBalance(member.getBalance().add(amount));
memberMapper.updateById(member);
// 记录流水...
}
- 计费时间误差处理:
java复制public long calculateUsedTime(Date startTime, Date endTime) {
// 使用Joda-Time处理时间计算更准确
return Minutes.minutesBetween(
new DateTime(startTime),
new DateTime(endTime)
).getMinutes();
}
6.2 开发心得
在实际开发过程中,有几个关键点值得特别注意:
-
事务边界划分:对于充值、消费等涉及金额变动的操作,务必确保事务的完整性,避免出现部分成功的情况。
-
时间处理:网咖系统对时间敏感,所有时间相关操作都应使用服务器时间,避免依赖客户端时间。
-
并发控制:会员余额、机器状态等共享资源需要做好并发控制,可以使用乐观锁或悲观锁策略。
-
数据一致性:定期对账非常重要,我们开发了每日对账功能,确保会员余额、消费记录和充值记录三者一致。
这个项目让我深刻理解了SpringBoot在实际业务场景中的应用,特别是在处理复杂业务逻辑时的优雅解决方案。通过合理的架构设计和代码组织,即使是相对复杂的网咖管理系统,也能保持代码的可维护性和扩展性。
