档案管理系统按验收次数收费功能的实操开发指南

一、技术选型与数据库表结构设计

在开发档案管理系统的计费模块时,为了确保系统的高并发处理能力和数据的一致性,本指南采用 Spring Boot 2.7 + MyBatis Plus + MySQL 8.0 作为核心技术栈。核心逻辑在于将“验收”动作与“费用计算”强绑定,确保每一次验收操作都能准确触发计费。

我们需要在 MySQL 中设计三张核心表:档案项目表(t_project)计费规则表(t_billing_rule)以及验收记录表(t_acceptance_record)。请直接执行以下 SQL 脚本完成数据库初始化:

```sql -- 创建档案项目表,用于存储项目基础信息及当前的验收状态 CREATE TABLE `t_project` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '项目ID', `project_name` varchar(100) NOT NULL COMMENT '项目名称', `total_acceptance_count` int(11) DEFAULT '0' COMMENT '累计验收次数', `accumulated_fee` decimal(10,2) DEFAULT '0.00' COMMENT '累计产生费用', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='档案项目表'; -- 创建计费规则表,定义按次收费的单价 CREATE TABLE `t_billing_rule` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '规则ID', `rule_name` varchar(50) NOT NULL COMMENT '规则名称', `unit_price` decimal(10,2) NOT NULL COMMENT '单次验收单价(元)', `is_active` tinyint(1) DEFAULT '1' COMMENT '是否生效:1-生效,0-失效', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='计费规则表'; -- 插入一条默认计费规则:每次验收收费 50.00 元 INSERT INTO `t_billing_rule` (`rule_name`, `unit_price`, `is_active`) VALUES ('默认按次收费', 50.00, 1); -- 创建验收记录表,用于记录每一次验收的流水,支持对账 CREATE TABLE `t_acceptance_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '记录ID', `project_id` bigint(20) NOT NULL COMMENT '关联的项目ID', `acceptance_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '验收时间', `current_count` int(11) NOT NULL COMMENT '当前是第几次验收', `fee_generated` decimal(10,2) NOT NULL COMMENT '本次产生的费用', PRIMARY KEY (`id`), KEY `idx_project_id` (`project_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='验收记录表'; ```

二、Spring Boot 项目构建与依赖配置

创建一个名为 archive-billing-system 的 Spring Boot 项目。在 pom.xml 中引入必要的依赖。为了简化代码量,我们使用 Lombok 来减少 Getter/Setter 的编写,使用 MyBatis Plus 来简化 CRUD 操作。

请确保你的 pom.xml 包含以下核心依赖:

```xml org.springframework.boot spring-boot-starter-web mysql mysql-connector-java runtime com.baomidou mybatis-plus-boot-starter 3.5.2 org.projectlombok lombok true ```

接下来,配置 application.yml 文件,连接到刚才创建的数据库。请将 usernamepassword 替换为你本地的数据库账号密码。

```yaml server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/archive_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 username: root password: your_password mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 开发环境打印SQL日志 global-config: db-config: logic-delete-field: deleted 全局逻辑删除字段值 logic-delete-value: 1 逻辑已删除值 logic-not-delete-value: 0 逻辑未删除值 ```

三、实体类与 Mapper 层代码实现

我们需要创建对应的实体类(Entity)和数据访问层(Mapper)。为了节省篇幅,这里直接展示核心代码。请在 com.example.archive.entity 包下创建以下类:

1. Project.java (项目实体)

```java package com.example.archive.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data @TableName("t_project") public class Project { @TableId(type = IdType.AUTO) private Long id; private String projectName; private Integer totalAcceptanceCount; private BigDecimal accumulatedFee; private LocalDateTime createTime; } ```

2. BillingRule.java (计费规则实体)

```java package com.example.archive.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; @Data @TableName("t_billing_rule") public class BillingRule { @TableId(type = IdType.AUTO) private Long id; private String ruleName; private BigDecimal unitPrice; private Integer isActive; } ```

3. AcceptanceRecord.java (验收记录实体)

```java package com.example.archive.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Data @TableName("t_acceptance_record") public class AcceptanceRecord { @TableId(type = IdType.AUTO) private Long id; private Long projectId; private LocalDateTime acceptanceTime; private Integer currentCount; private BigDecimal feeGenerated; } ```

接着,在 com.example.archive.mapper 包下创建对应的 Mapper 接口,只需继承 BaseMapper 即可获得基础 CRUD 能力:

```java package com.example.archive.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.archive.entity.Project; import org.apache.ibatis.annotations.Mapper; @Mapper public interface ProjectMapper extends BaseMapper {} @Mapper public interface BillingRuleMapper extends BaseMapper {} @Mapper public interface AcceptanceRecordMapper extends BaseMapper {} ```

四、按验收次数计费核心业务逻辑开发

这是本系统的核心部分。我们需要编写一个服务,当用户点击“验收”按钮时,系统自动执行以下步骤:

  • 加锁查询项目信息:防止并发验收导致计数错误。
  • 查询生效的计费规则:获取当前的单价。
  • 计算费用:累计次数 +1,累计费用 = 原费用 + 单价。
  • 更新数据库:更新项目表,并插入一条验收记录。

档案管理系统按验收次数收费功能的实操开发指南

com.example.archive.service 包下创建 AcceptanceService.java

```java package com.example.archive.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.example.archive.entity.; import com.example.archive.mapper.; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; @Service public class AcceptanceService { @Autowired private ProjectMapper projectMapper; @Autowired private BillingRuleMapper billingRuleMapper; @Autowired private AcceptanceRecordMapper acceptanceRecordMapper; / 核心方法:执行验收并扣费 @param projectId 项目ID / @Transactional(rollbackFor = Exception.class) // 开启事务,保证数据一致性 public void executeAcceptance(Long projectId) { // 1. 查询项目,使用悲观锁 (for update) 防止并发问题 // 注意:MyBatis Plus 默认不支持 for update 写法,这里简化处理,假设在Controller层已控制或单机低并发 // 生产环境建议在 SQL 中手动加锁,或者使用 Redis 分布式锁 Project project = projectMapper.selectById(projectId); if (project == null) { throw new RuntimeException("项目不存在,ID: " + projectId); } // 2. 查询当前生效的计费规则 QueryWrapper ruleQuery = new QueryWrapper<>(); ruleQuery.eq("is_active", 1); BillingRule rule = billingRuleMapper.selectOne(ruleQuery); if (rule == null) { throw new RuntimeException("系统未配置计费规则,无法验收"); } // 3. 计算新的状态 BigDecimal unitPrice = rule.getUnitPrice(); int oldCount = project.getTotalAcceptanceCount() == null ? 0 : project.getTotalAcceptanceCount(); int newCount = oldCount + 1; BigDecimal oldFee = project.getAccumulatedFee() == null ? BigDecimal.ZERO : project.getAccumulatedFee(); BigDecimal newFee = oldFee.add(unitPrice); // 4. 更新项目表 project.setTotalAcceptanceCount(newCount); project.setAccumulatedFee(newFee); projectMapper.updateById(project); // 5. 插入验收记录流水 AcceptanceRecord record = new AcceptanceRecord(); record.setProjectId(projectId); record.setAcceptanceTime(LocalDateTime.now()); record.setCurrentCount(newCount); record.setFeeGenerated(unitPrice); // 本次产生费用即为单价 acceptanceRecordMapper.insert(record); } } ```

注意: 在高并发场景下,上述代码中的 selectById 可能会导致脏读。如果是生产环境,建议修改 Mapper 方法使用 SELECT FROM t_project WHERE id = {id} FOR UPDATE 来实现数据库层面的悲观锁,或者使用 Redis 的 SETNX 实现分布式锁。本示例为了保持代码清晰,使用了 @Transactional 保证原子性。

五、接口层实现与功能验证

我们需要提供一个 RESTful API 供前端调用。创建 AcceptanceController.java

```java package com.example.archive.controller; import com.example.archive.service.AcceptanceService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api/acceptance") public class AcceptanceController { @Autowired private AcceptanceService acceptanceService; / 验收接口 @param projectId 项目ID @return 操作结果 / @PostMapping("/execute/{projectId}") public Map accept(@PathVariable Long projectId) { try { acceptanceService.executeAcceptance(projectId); Map result = new HashMap<>(); result.put("code", 200); result.put("message", "验收成功,费用已结算"); return result; } catch (Exception e) { Map result = new HashMap<>(); result.put("code", 500); result.put("message", "验收失败:" + e.getMessage()); return result; } } } ```

至此,代码编写完毕。现在我们进行功能验证。假设数据库中 t_project 表已有一条 ID 为 1 的数据。

1. 启动项目

运行 Spring Boot 主类,确保端口 8080 启动成功,无报错。

2. 模拟验收请求

使用 Postman 或 curl 发送 POST 请求。我们将连续调用两次,观察计费是否累加。

```bash 第一次验收 curl -X POST "http://localhost:8080/api/acceptance/execute/1" 预期返回 {"code":200,"message":"验收成功,费用已结算"} ```

3. 数据库验证

执行完第一次请求后,查询数据库:

```sql SELECT FROM t_project WHERE id = 1; SELECT FROM t_acceptance_record WHERE project_id = 1; ```

你应该能看到 t_project 表中 total_acceptance_count 变为 1,accumulated_fee 变为 50.00。t_acceptance_record 表中新增了一条记录。

再次执行 curl 命令进行第二次验收。再次查询数据库,total_acceptance_count 应变为 2,accumulated_fee 应变为 100.00。这证明了按次数累加计费逻辑已成功落地。

AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统