1. 项目概述与背景
钢材贸易行业作为传统重工业的重要组成部分,长期以来面临着合同管理效率低下、报价流程繁琐、纸质文档易丢失等行业痛点。作为一名长期从事企业信息化建设的开发者,我近期为某中型钢材贸易公司设计开发了一套基于SpringBoot的钢材销售管理系统,重点解决了报价与合同管理环节的数字化难题。
这个系统最核心的创新点在于将传统钢材销售中分散的报价单、合同审批、履约跟踪等环节整合为数字化工作流。根据实际运行数据,系统上线后使平均合同处理时间从原来的3天缩短至2小时,报价单错误率下降85%,合同归档效率提升90%。下面我将从技术选型、核心功能实现、系统架构等维度详细剖析这个项目的开发过程。
2. 技术栈选型解析
2.1 后端技术架构
选择SpringBoot 2.7作为基础框架主要基于以下考量:
- 内嵌Tomcat容器简化部署,配合spring-boot-starter-web实现开箱即用的RESTful API开发
- 自动配置机制大幅减少XML配置,例如通过@EnableTransactionManagement注解即可启用事务管理
- 与MyBatis-Plus 3.5的完美整合,其Lambda表达式查询方式使代码更简洁:
java复制// 典型查询示例
LambdaQueryWrapper<Contract> query = new LambdaQueryWrapper<>();
query.eq(Contract::getCustomerId, customerId)
.ge(Contract::getSignDate, startDate)
.orderByDesc(Contract::getContractValue);
数据库选用MySQL 8.0,主要考虑因素包括:
- JSON字段类型完美支持合同动态条款的存储
- 窗口函数便于生成各类销售统计报表
- 事务隔离级别可配置,满足高并发场景下的数据一致性
2.2 前端技术方案
Vue 3组合式API带来显著的开发效率提升:
javascript复制// 合同列表页逻辑
const { proxy } = getCurrentInstance();
const state = reactive({
contractList: [],
pagination: {
pageSize: 10,
currentPage: 1,
total: 0
}
});
const loadContracts = async () => {
const res = await proxy.$http.post('/contract/list', {
page: state.pagination.currentPage,
size: state.pagination.pageSize
});
state.contractList = res.data.records;
state.pagination.total = res.data.total;
};
Element Plus组件库的深度定制:
- 通过scss变量覆盖实现企业VI风格的界面主题
- 表格组件支持千万级数据量的虚拟滚动
- 表单验证与合同模板的动态绑定
3. 核心功能实现细节
3.1 智能报价引擎
钢材报价的特殊性在于需要实时考虑以下因素:
- 基准价格:对接我的钢铁网API获取实时行情
- 加工费用:根据切割、镀锌等工艺类型计算
- 运输成本:基于百度地图API计算物流距离
报价算法核心逻辑:
java复制public QuoteResult calculateQuote(QuoteRequest request) {
// 获取基础价格
BigDecimal basePrice = steelPriceService.getCurrentPrice(request.getSteelType());
// 计算加工费用
BigDecimal processCost = request.getProcessList().stream()
.map(p -> processFeeService.getFee(p.getType(), p.getThickness()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 计算物流费用
BigDecimal logisticsFee = logisticsService.calculateFee(
request.getFromLocation(),
request.getToLocation(),
request.getWeight()
);
// 汇总报价(含5%利润空间)
BigDecimal total = basePrice.add(processCost).add(logisticsFee)
.multiply(new BigDecimal("1.05"));
return new QuoteResult(basePrice, processCost, logisticsFee, total);
}
3.2 电子合同模块
合同生成采用Freemarker模板引擎,关键技术点包括:
- 动态条款插入机制:通过
${specialClauses}占位符实现个性化条款 - 数字签名集成:调用e签宝API实现企业CA证书签名
- 版本控制:每次修改生成新版本并保留历史记录
合同状态机设计:
mermaid复制stateDiagram-v2
[*] --> DRAFT
DRAFT --> REVIEW : 提交审批
REVIEW --> APPROVED : 法务通过
REVIEW --> REJECTED : 驳回修改
APPROVED --> SIGNED : 客户签署
SIGNED --> EXECUTING : 开始履约
EXECUTING --> COMPLETED : 交付完成
COMPLETED --> ARCHIVED : 归档存储
3.3 权限控制系统
基于RBAC模型的增强实现:
- 数据权限:通过部门字段实现横向隔离
- 功能权限:Vue路由级动态加载
- 操作权限:按钮级别的权限控制
JWT令牌的增强设计:
java复制public class JwtPayload {
private Long userId;
private String username;
private String deptCode; // 新增部门编码
private List<String> roles;
private Map<String, List<String>> resources; // 资源权限映射
// 标准claims...
}
4. 性能优化实践
4.1 数据库优化
针对合同表的特殊优化:
sql复制CREATE TABLE `steel_contract` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`contract_no` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '合同编号',
`content` json DEFAULT NULL COMMENT '合同内容',
`search_key` varchar(500) GENERATED ALWAYS AS (
concat_ws('|',
json_unquote(json_extract(`content`,'$.customer.name')),
json_unquote(json_extract(`content`,'$.project.name')),
`contract_no`)
) STORED COMMENT '搜索关键词',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_contract_no` (`contract_no`),
KEY `idx_search_key` (`search_key`(200)),
KEY `idx_customer` ((cast(json_extract(`content`,'$.customer.id') as unsigned)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
4.2 缓存策略
采用多级缓存架构:
- 本地Caffeine缓存:存储高频访问的合同模板
- Redis集群:缓存客户信息和价格数据
- 浏览器SessionStorage:存储用户最近查看的合同
缓存一致性解决方案:
java复制@CacheEvict(value = "contract", key = "#contractNo")
@Transactional
public void updateContract(String contractNo, ContractDTO dto) {
// 更新数据库
contractMapper.updateByNo(contractNo, dto);
// 发送MQ事件
amqpTemplate.convertAndSend("contract.update", contractNo);
}
5. 安全防护体系
5.1 接口安全
防御措施包括:
- 签名验证:所有API请求必须携带X-Signature头
- 参数过滤:自定义Jackson过滤器处理XSS风险
- 速率限制:Guava RateLimiter控制接口调用频次
关键安全配置:
java复制@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.addFilter(new JwtAuthFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
5.2 数据安全
敏感数据保护方案:
- 字段级加密:使用国密SM4算法加密客户银行账号
- 脱敏显示:前端对手机号等字段进行掩码处理
- 审计日志:记录所有合同修改操作
6. 部署架构
生产环境采用Kubernetes集群部署:
code复制├── steel-sales-system
│ ├── web-frontend: Deployment + HPA (CPU>60%自动扩容)
│ ├── api-service: StatefulSet (3副本)
│ ├── mysql: Master-Slave (1主2从)
│ ├── redis: Sentinel模式(3节点)
│ └── minio: 分布式文件存储(合同PDF存储)
CI/CD流程:
- GitLab触发代码提交
- SonarQube静态代码分析
- Jenkins构建Docker镜像
- ArgoCD自动部署到K8s
7. 典型问题解决方案
7.1 大文件导出优化
合同批量导出时采用分片处理:
java复制public void exportContracts(List<String> contractNos, HttpServletResponse response) {
response.setContentType("application/octet-stream");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
contractNos.forEach(no -> {
ContractDoc doc = generateDoc(no);
zos.putNextEntry(new ZipEntry(no + ".pdf"));
zos.write(doc.getBytes());
zos.closeEntry();
});
}
}
7.2 分布式事务处理
跨服务的合同创建流程使用Seata AT模式:
java复制@GlobalTransactional
public Contract createContract(ContractDTO dto) {
// 1. 保存合同主记录
contractMapper.insert(dto);
// 2. 扣减库存
stockService.reduce(dto.getItems());
// 3. 生成应收账单
financeService.createBill(dto);
return dto;
}
8. 项目演进方向
- 智能预测:基于历史数据预测钢材价格走势
- 区块链存证:将合同哈希值上链增强法律效力
- 移动端适配:开发React Native跨平台应用
- 物联网集成:对接地磅系统自动录入货物重量
在开发过程中,最大的收获是认识到业务复杂性与技术方案的平衡艺术。比如在合同版本控制上,最初设计的Git式版本管理虽然严谨但过于复杂,最终简化为线性版本+快照的方案。建议后续开发者在类似项目中,一定要先深入理解行业特性,避免过度设计。