1. 项目概述:SpringBoot+Vue+MySQL全栈招投标系统
这套在线招投标系统采用当前主流的前后端分离架构,后端基于SpringBoot 2.x技术栈实现业务逻辑与数据交互,前端使用Vue 3组合式API开发管理界面,数据存储采用MySQL 8.0关系型数据库。系统开箱即用,包含完整的用户权限管理、招标项目管理、投标文件提交、评标流程控制等核心功能模块。
我在实际部署测试中发现,这套代码特别适合需要快速搭建招投标平台的中小企业或政府机构。相比市面上的商业软件,它提供了三个显著优势:一是采用MIT开源协议可自由二次开发;二是前后端代码结构清晰,技术栈选型符合当前企业级开发标准;三是自带Swagger接口文档和Vue路由权限配置示例,降低了定制化开发门槛。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与系统部署
2.1 基础环境配置
开发环境需要准备:
- JDK 1.8+(推荐Amazon Corretto 11)
- Node.js 14.x+(注意需要与Vue CLI兼容版本)
- MySQL 8.0(必须开启INNODB引擎)
- Maven 3.6+(用于SpringBoot依赖管理)
- Redis 5.0+(用于会话管理和缓存)
重要提示:MySQL必须配置为大小写敏感模式(lower_case_table_names=0),否则启动时会报表不存在错误。这是SpringBoot JPA的命名策略与MySQL默认配置冲突导致的常见问题。
2.2 数据库初始化
源码包中的/sql/tender_system.sql文件包含完整的DDL和示例数据。导入时需特别注意:
sql复制-- 创建专用数据库(字符集必须为utf8mb4)
CREATE DATABASE tender_system
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 执行初始化脚本前需要设置SQL模式
SET GLOBAL sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
2.3 后端服务启动
SpringBoot应用的配置文件application.yml需要修改以下关键参数:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/tender_system?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: yourpassword
redis:
host: 127.0.0.1
port: 6379
password:
启动命令:
bash复制# 编译打包
mvn clean package -DskipTests
# 运行jar包
java -jar target/tender-system-1.0.0.jar
2.4 前端服务启动
Vue前端需要配置API代理地址,修改vue.config.js:
javascript复制devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
安装依赖并运行:
bash复制npm install --registry=https://registry.npm.taobao.org
npm run serve
3. 核心功能模块解析
3.1 多级权限控制系统
系统采用RBAC(基于角色的访问控制)模型,通过Spring Security + JWT实现认证授权。核心设计亮点包括:
- 动态菜单权限:根据用户角色从数据库加载Vue路由配置
- 数据权限过滤:通过MyBatis拦截器自动添加部门数据过滤条件
- 操作日志审计:使用AOP记录敏感操作
权限表结构设计:
sql复制CREATE TABLE `sys_role` (
`role_id` bigint NOT NULL AUTO_INCREMENT,
`role_name` varchar(30) NOT NULL,
`role_key` varchar(100) NOT NULL,
`data_scope` char(1) DEFAULT '1'
);
CREATE TABLE `sys_menu` (
`menu_id` bigint NOT NULL AUTO_INCREMENT,
`menu_name` varchar(50) NOT NULL,
`perms` varchar(100) DEFAULT NULL,
`component` varchar(200) DEFAULT NULL
);
3.2 招标流程状态机
招标业务采用状态模式实现流程控制,主要状态转换包括:
- 草稿 → 已发布(需财务审核)
- 已发布 → 招标中(自动触发)
- 招标中 → 评标中(截止时间到达)
- 评标中 → 已中标(需评委确认)
状态机实现核心代码:
java复制public enum TenderStatus {
DRAFT {
@Override
public void publish(TenderContext context) {
// 验证预算金额等业务规则
if(context.getBudget() <= 0) {
throw new IllegalStateException("预算金额必须大于0");
}
context.changeStatus(PUBLISHED);
}
},
PUBLISHED {
@Override
public void beginBidding(TenderContext context) {
// 自动过渡到招标中状态
context.changeStatus(BIDDING);
}
},
// 其他状态省略...
}
3.3 投标文件安全处理
系统对投标文件的上传和存储做了多重安全防护:
- 文件类型白名单校验(仅允许PDF/DOCX格式)
- 病毒扫描(集成ClamAV开源杀毒引擎)
- 文件加密存储(使用AES-256加密上传文件)
- 数字水印(自动添加投标方信息隐形水印)
文件上传核心逻辑:
java复制@PostMapping("/upload")
public Result upload(@RequestParam MultipartFile file) {
// 1. 校验文件类型
String ext = FilenameUtils.getExtension(file.getOriginalFilename());
if(!ALLOWED_EXTENSIONS.contains(ext.toLowerCase())) {
return Result.error("仅支持"+ALLOWED_EXTENSIONS+"格式");
}
// 2. 病毒扫描
ScanResult scanResult = clamAvScanner.scan(file.getBytes());
if(scanResult.getStatus() != ScanResult.Status.PASSED) {
return Result.error("文件安全检测未通过");
}
// 3. 加密存储
String fileKey = AESUtil.encrypt(
file.getOriginalFilename(),
systemConfig.getFileSecret()
);
storageService.upload(file.getInputStream(), fileKey);
return Result.ok(fileKey);
}
4. 二次开发指南
4.1 扩展自定义审批流程
如需增加招标项目审批环节,可按以下步骤操作:
- 数据库新增审批表:
sql复制CREATE TABLE `tender_approval` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tender_id` bigint NOT NULL,
`approver_id` bigint NOT NULL,
`status` tinyint DEFAULT 0 COMMENT '0-待审批 1-已通过 2-已拒绝',
`comment` varchar(500) DEFAULT NULL,
PRIMARY KEY (`id`)
);
- 实现审批服务接口:
java复制public interface ApprovalService {
void startApprovalFlow(Long tenderId);
void approve(Long approvalId, Long userId, boolean passed);
boolean checkApprovalComplete(Long tenderId);
}
- 在招标状态机中插入审批环节:
java复制PUBLISHED {
@Override
public void beginBidding(TenderContext context) {
// 先检查审批是否完成
if(!approvalService.checkApprovalComplete(context.getId())) {
throw new IllegalStateException("存在未完成的审批流程");
}
context.changeStatus(BIDDING);
}
}
4.2 集成短信通知功能
实际部署时需要接入短信服务通知投标方,推荐使用阿里云短信服务:
- 添加SDK依赖:
xml复制<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
- 配置短信模板:
java复制@Configuration
public class SmsConfig {
@Value("${aliyun.sms.accessKeyId}")
private String accessKeyId;
@Bean
public IAcsClient acsClient() {
IClientProfile profile = DefaultProfile.getProfile(
"cn-hangzhou",
accessKeyId,
accessKeySecret);
return new DefaultAcsClient(profile);
}
}
- 实现通知服务:
java复制public void sendBidOpeningNotice(Long tenderId) {
List<Bid> bids = bidMapper.selectByTenderId(tenderId);
bids.forEach(bid -> {
SendSmsRequest request = new SendSmsRequest();
request.setPhoneNumbers(bid.getContactPhone());
request.setSignName("招标系统");
request.setTemplateCode("SMS_123456");
request.setTemplateParam("{\"code\":\""+bid.getBidCode()+"\"}");
try {
acsClient.getAcsResponse(request);
} catch (ClientException e) {
log.error("短信发送失败", e);
}
});
}
5. 生产环境部署建议
5.1 性能优化配置
针对高并发场景需要调整以下参数:
- MySQL优化(my.cnf):
ini复制[mysqld]
innodb_buffer_pool_size = 4G
innodb_log_file_size = 512M
max_connections = 500
thread_cache_size = 50
- SpringBoot线程池配置:
yaml复制server:
tomcat:
max-threads: 200
min-spare-threads: 20
- Vue生产构建优化:
javascript复制// vue.config.js
module.exports = {
productionSourceMap: false,
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'all',
maxSize: 244 * 1024 // 拆分包大小
}
}
}
}
5.2 安全加固措施
- 接口防刷配置:
java复制@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(
new RateLimitFilter(redisTemplate),
UsernamePasswordAuthenticationFilter.class);
}
}
- 敏感数据脱敏处理:
java复制@JsonComponent
public class SensitiveDataSerializer {
public static class PhoneSerializer extends JsonSerializer<String> {
@Override
public void serialize(
String value,
JsonGenerator gen,
SerializerProvider provider
) throws IOException {
gen.writeString(
value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")
);
}
}
}
- 定期更换JWT密钥:
java复制@Scheduled(cron = "0 0 0 * * ?")
public void rotateJwtSecret() {
String newSecret = RandomStringUtils.randomAlphanumeric(32);
redisTemplate.opsForValue().set(
"jwt:current:secret",
newSecret,
48, TimeUnit.HOURS
);
// 旧密钥保留24小时用于token过渡
redisTemplate.opsForValue().set(
"jwt:previous:secret",
currentSecret,
24, TimeUnit.HOURS
);
}
这套系统在我参与过的多个招投标平台项目中表现出色,特别是在处理并发投标和复杂评审流程时稳定性良好。建议初次部署时重点关注权限配置和状态机流转测试,这两个模块最容易出现业务逻辑问题。对于需要深度定制的场景,可以优先考虑扩展审批流程和集成电子签章功能,这是目前客户最常提出的两个增强需求。
