1. 项目背景与核心价值
去年帮学弟调试毕业设计时,接触到一个典型的供应商管理系统案例。这种基于SpringBoot+Vue的前后端分离架构,目前已成为高校计算机专业毕业设计的热门选题。究其原因,在于它完美涵盖了企业级应用开发的完整技术栈,从后端API设计到前端工程化实践都能得到充分锻炼。
这类系统通常需要实现供应商信息管理、合同跟踪、订单处理、绩效评估等核心业务模块。我在实际指导过程中发现,很多同学虽然能跑通基础功能,但在权限控制、数据校验、接口安全等企业级必备特性上往往存在明显短板。下面就以技术复盘的形式,分享一个毕业设计级供应商管理系统的完整实现方案。
2. 技术选型与架构设计
2.1 后端技术栈
采用SpringBoot 2.7作为基础框架,其优势在于:
- 内嵌Tomcat简化部署
- 自动配置减少XML编写
- 丰富的Starter依赖(数据访问用spring-boot-starter-data-jpa,安全控制用spring-security)
数据库选用MySQL 8.0,考虑到:
- 高校实验室环境普遍支持
- 窗口函数等高级特性便于复杂统计
- 与JPA的Hibernate实现兼容性好
xml复制<!-- 典型POM依赖示例 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
2.2 前端技术栈
Vue 3组合式API相比选项式API更适合复杂业务场景:
- 更好的TypeScript支持
- 逻辑关注点集中
- 更灵活的逻辑复用
配套选用:
- Element Plus组件库(表单/表格等企业级组件齐全)
- Axios处理HTTP请求(需配置拦截器实现JWT自动携带)
- Vue Router实现动态路由(配合权限控制)
javascript复制// 典型axios拦截器配置
service.interceptors.request.use(config => {
if (store.getters.token) {
config.headers['Authorization'] = `Bearer ${getToken()}`
}
return config
})
3. 核心业务模块实现
3.1 供应商主数据管理
采用JPA动态查询实现多条件筛选:
java复制@Repository
public interface SupplierRepository extends JpaRepository<Supplier, Long>, JpaSpecificationExecutor<Supplier> {
}
// 使用Specification构建动态查询
public static Specification<Supplier> buildQuery(SupplierQuery query) {
return (root, criteriaQuery, builder) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(query.getName())) {
predicates.add(builder.like(root.get("name"), "%"+query.getName()+"%"));
}
// 其他条件...
return builder.and(predicates.toArray(new Predicate[0]));
};
}
注意:实体类需要添加@DynamicUpdate注解实现部分更新,避免全字段覆盖
3.2 合同生命周期管理
实现合同状态机时推荐使用枚举驱动:
java复制public enum ContractStatus {
DRAFT(1, "草稿"),
APPROVING(2, "审批中"),
EXECUTING(3, "执行中"),
COMPLETED(4, "已完成"),
TERMINATED(5, "已终止");
// 状态流转校验逻辑
public static void validateTransition(ContractStatus from, ContractStatus to) {
// 定义合法状态转换规则...
}
}
3.3 采购订单流程
订单生成时需要处理的事务要点:
- 库存预占检查(@Transactional隔离级别设为REPEATABLE_READ)
- 供应商评级验证(@Cacheable缓存评级结果)
- 操作日志记录(@Async异步写入日志表)
4. 关键难点解决方案
4.1 权限控制实现
RBAC模型结合前端动态路由:
java复制// 后端权限注解
@PreAuthorize("@ss.hasPermission('supplier:add')")
@PostMapping
public Result addSupplier(@Valid @RequestBody Supplier supplier) {
//...
}
// 前端路由过滤
const filterAsyncRoutes = (routes, roles) => {
return routes.filter(route => {
if (hasPermission(roles, route.meta?.roles)) {
if (route.children) {
route.children = filterAsyncRoutes(route.children, roles)
}
return true
}
return false
})
}
4.2 数据导出性能优化
百万级数据导出采用分页批处理:
java复制// 使用游标避免内存溢出
try (ScrollableResults scroll = session.createQuery("from Supplier")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY)) {
while (scroll.next()) {
Supplier s = (Supplier) scroll.get(0);
// 写入CSV...
session.evict(s); // 及时清除缓存
}
}
5. 毕业论文加分项实践
5.1 接口幂等性设计
采用token+redis方案:
- 前端预获取token(GET /api/token)
- 提交时携带token(POST请求头)
- 后端校验(Redis原子操作):
java复制Boolean success = redisTemplate.opsForValue()
.setIfAbsent("idempotent:"+token, "1", 5, TimeUnit.MINUTES);
if (!success) throw new IdempotentException();
5.2 审计日志实现
基于Hibernate Envers实现:
java复制@Entity
@Audited
public class Supplier {
//...
}
// 查询历史版本
AuditReader reader = AuditReaderFactory.get(entityManager);
List<Number> revisions = reader.getRevisions(Supplier.class, id);
6. 常见避坑指南
-
日期序列化问题:
- 前端axios需配置transformRequest处理Date类型
- 后端@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
-
跨域配置陷阱:
- 生产环境应配置具体域名而非"*"
- 需处理OPTIONS预检请求
-
事务失效场景:
- 自调用问题(AOP代理失效)
- 异常类型未配置(默认只回滚RuntimeException)
-
性能监控技巧:
- 启用SpringBoot Actuator
- 使用@Timed记录方法执行时间
这个系统在实现时特别要注意业务边界清晰,建议采用领域驱动设计(DDD)的思想划分模块。我在代码评审时发现,很多同学把供应商评价逻辑直接写在Controller里,这会导致后期难以维护。正确的做法是建立独立的rating领域服务,通过领域事件驱动状态变更。