1. 电子招投标系统架构设计
电子招投标系统作为企业采购和项目承包的重要平台,需要兼顾高效性、安全性和易用性。我们采用前后端分离架构,后端基于Spring Boot构建RESTful API服务,前端使用Vue.js实现响应式界面,这种组合既能保证系统性能,又能提供良好的用户体验。
1.1 技术栈选型考量
后端选择Spring Boot框架主要基于以下几个因素:
- 自动配置特性大幅减少XML配置
- 内嵌Tomcat容器简化部署流程
- 丰富的Starter依赖可快速集成常用组件
- 完善的生态体系(Spring Security、Spring Data等)
前端选用Vue.js的核心优势在于:
- 响应式数据绑定简化DOM操作
- 组件化开发提高代码复用率
- 渐进式框架易于学习和集成
- 丰富的UI库(如Element UI)加速开发
数据库方案采用MySQL+Redis组合:
- MySQL作为主数据库存储结构化数据
- Redis缓存热点数据(如招标列表、用户权限)
- 文件存储使用MinIO构建私有对象存储服务
1.2 系统模块划分逻辑
系统采用模块化设计,主要分为四个核心模块:
-
用户中心模块
- 实现RBAC(基于角色的访问控制)模型
- 区分招标方、投标方、评标专家三类角色
- 集成短信/邮箱验证码登录
-
招标管理模块
- 招标公告发布与状态机管理
- 招标文件版本控制
- 投标方资质预审流程
-
投标管理模块
- 投标文件加密上传
- 投标保证金缴纳记录
- 投标有效性校验
-
评标管理模块
- 多专家评分汇总
- 自动计分算法实现
- 评标结果公示与质疑处理
提示:模块划分遵循单一职责原则,每个模块对应独立的Git仓库,通过Maven多模块或Monorepo方式管理。
2. 后端核心实现细节
2.1 认证授权方案
采用JWT+Spring Security实现无状态认证:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/tender/**").hasAnyRole("TENDERER","ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
关键实现要点:
- 自定义UserDetailsService加载用户权限
- JWT令牌设置合理过期时间(建议2-4小时)
- 使用黑名单机制处理令牌注销
- 敏感接口增加二次认证(如短信验证码)
2.2 文件处理方案
招标文件上传采用分块上传策略:
java复制@PostMapping("/upload")
public ResponseEntity<UploadResult> chunkUpload(
@RequestParam("file") MultipartFile file,
@RequestParam("chunkNumber") int chunkNumber,
@RequestParam("totalChunks") int totalChunks) {
String fileMd5 = DigestUtils.md5DigestAsHex(file.getBytes());
String chunkKey = "file:chunk:" + fileMd5 + ":" + chunkNumber;
redisTemplate.opsForValue().set(chunkKey, file.getBytes());
if (chunkNumber == totalChunks) {
fileService.mergeChunks(fileMd5, totalChunks);
}
return ResponseEntity.ok(new UploadResult(chunkNumber, totalChunks));
}
文件存储安全措施:
- 上传文件病毒扫描(集成ClamAV)
- 文件内容类型白名单校验
- 存储路径随机化防止遍历攻击
- 定期清理临时分块文件
2.3 评标算法服务化
将评标算法封装为独立服务:
java复制@Service
public class EvaluationServiceImpl implements EvaluationService {
@Override
public EvaluationResult autoEvaluate(Tender tender, List<Bid> bids) {
// 1. 资质符合性检查
bids = filterQualifiedBids(bids, tender.getRequirements());
// 2. 价格分计算(合理低价法)
bids.sort(Comparator.comparing(Bid::getTotalPrice));
double minPrice = bids.get(0).getTotalPrice();
// 3. 技术标评分汇总
bids.forEach(bid -> {
double techScore = bid.getTechEvaluations().stream()
.mapToDouble(Evaluation::getScore).average().orElse(0);
bid.setFinalScore(techScore * 0.7 + (minPrice/bid.getTotalPrice())*30);
});
return new EvaluationResult(bids);
}
}
3. 前端关键实现技术
3.1 动态路由与权限控制
基于用户角色过滤路由表:
javascript复制// 路由配置
const routes = [
{
path: '/tender',
component: Layout,
meta: { roles: ['tenderer', 'admin'] },
children: [
{ path: 'create', component: TenderCreate }
]
}
]
// 路由守卫
router.beforeEach((to, from, next) => {
const userRoles = store.getters.roles
if (to.meta.roles && !to.meta.roles.some(role => userRoles.includes(role))) {
next('/403')
} else {
next()
}
})
3.2 投标文件上传优化
实现断点续传功能:
vue复制<template>
<el-upload
:action="uploadUrl"
:before-upload="checkFile"
:on-progress="handleProgress"
:data="uploadData"
:headers="headers"
multiple
:file-list="fileList">
<el-button type="primary">选择投标文件</el-button>
</el-upload>
</template>
<script>
export default {
methods: {
checkFile(file) {
const isLt2G = file.size / 1024 / 1024 < 2048
if (!isLt2G) {
this.$message.error('文件大小不能超过2GB')
return false
}
return true
},
handleProgress(event, file) {
this.$emit('progress', {
percent: event.percent,
file: file
})
}
}
}
</script>
3.3 实时通知实现
使用WebSocket推送评标进度:
javascript复制// 建立WebSocket连接
const socket = new WebSocket(`wss://${location.host}/api/ws`)
socket.onmessage = (event) => {
const data = JSON.parse(event.data)
switch (data.type) {
case 'EVALUATION_PROGRESS':
this.updateProgress(data.payload)
break
case 'BID_STATUS':
this.updateBidStatus(data.payload)
break
}
}
4. 系统安全防护体系
4.1 数据加密方案
采用分层加密策略:
- 传输层:TLS 1.3加密通信
- 存储层:
- 用户密码:BCrypt强哈希
- 投标文件:AES-256加密
- 加密密钥:RSA非对称保护
密钥管理实现:
java复制@Configuration
public class CryptoConfig {
@Bean
public AES256 aes256() throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
return new AES256(keyGen.generateKey());
}
@Bean
public RSAKeyPair rsaKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048);
KeyPair keyPair = keyPairGen.generateKeyPair();
return new RSAKeyPair(keyPair);
}
}
4.2 防攻击措施
- 接口防刷:
java复制@Aspect
@Component
public class RateLimitAspect {
private final RateLimiter limiter = RateLimiter.create(100); // 100次/秒
@Around("@annotation(rateLimit)")
public Object around(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {
if (limiter.tryAcquire()) {
return pjp.proceed();
}
throw new BusinessException("请求过于频繁");
}
}
- SQL注入防护:
- 强制使用JPA/Hibernate参数化查询
- 禁止拼接SQL语句
- 定期执行SQL注入测试
- XSS防护:
- 前端使用DOMPurify净化输入
- 后端统一进行HTML实体编码
- 设置Content-Security-Policy头
5. 部署与运维方案
5.1 容器化部署
Docker Compose编排示例:
yaml复制version: '3.8'
services:
backend:
build: ./backend
ports:
- "8080:8080"
environment:
- DB_URL=jdbc:mysql://mysql:3306/bidding
- REDIS_HOST=redis
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
mysql:
image: mysql:8.0
volumes:
- mysql_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=bidding
redis:
image: redis:6
ports:
- "6379:6379"
volumes:
mysql_data:
5.2 监控与日志
- 监控指标采集:
- JVM指标:Micrometer + Prometheus
- 业务指标:自定义MeterRegistry
- 前端性能:Sentry监控
- 日志收集方案:
java复制@Configuration
public class LogbackConfig {
@Bean
public LogstashTcpSocketAppender logstashAppender() {
LogstashTcpSocketAppender appender = new LogstashTcpSocketAppender();
appender.setDestination("logstash:5044");
appender.setEncoder(new LogstashEncoder());
return appender;
}
}
- 告警规则示例:
- 错误率 > 1%持续5分钟
- 平均响应时间 > 2s
- JVM内存使用 > 90%
6. 开发实践与经验总结
6.1 常见问题排查
- 跨域问题解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST")
.allowCredentials(true)
.maxAge(3600);
}
}
- 文件上传大小限制:
properties复制# application.properties
spring.servlet.multipart.max-file-size=2GB
spring.servlet.multipart.max-request-size=2GB
- Vue生产环境调试:
javascript复制// vue.config.js
module.exports = {
configureWebpack: {
devtool: process.env.NODE_ENV === 'production'
? 'source-map'
: 'eval-source-map'
}
}
6.2 性能优化建议
- 后端优化:
- 启用Spring Boot Actuator监控端点
- 添加HikariCP连接池配置
- 使用@Cacheable注解缓存热点数据
- 前端优化:
- 路由懒加载
- 第三方库按需引入
- 启用Gzip压缩
- 使用WebP格式图片
- 数据库优化:
- 招标表添加状态索引
- 分页查询使用延迟关联
- 定期执行ANALYZE TABLE
6.3 扩展方向建议
- 功能扩展:
- 电子合同签署(集成e签宝)
- 保证金自动退付
- 移动端小程序接入
- 技术深化:
- 引入Elasticsearch实现招标搜索
- 使用WebRTC实现远程述标
- 区块链存证关键操作
- 架构演进:
- 服务拆分微服务架构
- 引入消息队列削峰填谷
- 多活数据中心部署