用Vue+SpringBoot+MySQL做个超市商品管理系统,我踩过的坑你别再踩了(附完整源码)
VueSpringBootMySQL超市商品管理系统实战避坑指南第一次用Vue和SpringBoot做超市管理系统时我对着满屏的报错信息差点崩溃。前后端联调时浏览器控制台的红字、数据库连接池莫名其妙耗尽、MyBatis Plus的乐观锁配置总是不生效...这些坑让我熬了三个通宵。现在我把这些血泪教训整理成这份实战手册帮你节省至少80%的调试时间。1. 技术选型与版本适配陷阱2023年SpringBoot 3.0发布后很多教程里的配置突然就失效了。我的环境组合是Vue 2.7 SpringBoot 3.1 MyBatis Plus 3.5.3.1这个搭配藏着几个致命暗礁前端依赖冲突典型症状[Vue warn]: Error in mounted hook: TypeError: Cannot read properties of undefined (reading get)这是因为vue-cli默认安装的axios版本可能与SpringBoot 3.1的HTTP客户端不兼容。解决方案// 正确姿势 npm install axios1.3.4 --save后端更是个雷区MyBatis Plus 3.5.3.1需要特殊配置才能适配SpringBoot 3.1# application.yml关键配置 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: del_flag logic-not-delete-value: 0 logic-delete-value: 1注意SpringBoot 3.x默认使用Jakarta EE 9所有javax包名都要改为jakarta2. 数据库设计中的隐藏成本最初设计的商品表差点导致性能灾难看看这个反面教材CREATE TABLE a_commodity ( id varchar(255) NOT NULL, area varchar(255) DEFAULT NULL, -- 区域名称冗余存储 shelves_id varchar(255) DEFAULT NULL, type_id varchar(255) DEFAULT NULL, -- 其余字段省略 PRIMARY KEY (id) );问题在于区域名称直接冗余存储修改时要同步更新所有商品记录没有为外键字段建立索引联查时性能暴跌优化后的方案ALTER TABLE a_commodity ADD INDEX idx_shelves (shelves_id), ADD INDEX idx_type (type_id); -- 联查时使用JOIN替代子查询 SELECT c.title, s.title as shelves, a.title as area FROM a_commodity c LEFT JOIN a_supermarket_shelves s ON c.shelves_id s.id LEFT JOIN a_supermarket_area a ON s.area_id a.id3. 前后端数据交互的魔鬼细节3.1 时间字段序列化问题SpringBoot 3.1默认的Jackson配置会把LocalDateTime序列化成这样createTime: [2023,8,15,14,30,45]前端Vue组件直接崩溃。解决方案// 后端配置 Bean public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { return builder - { builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); builder.deserializers(new LocalDateTimeDeserializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); }; }3.2 文件上传内存溢出用默认配置上传商品图片时超过10MB的文件会导致OOM错误// 正确配置 spring: servlet: multipart: max-file-size: 20MB max-request-size: 30MB location: /tmp/uploads前端对应的Axios配置const instance axios.create({ baseURL: /api, timeout: 30000, headers: { Content-Type: multipart/form-data }, transformRequest: [function (data) { const formData new FormData() Object.keys(data).forEach(key { formData.append(key, data[key]) }) return formData }] })4. 权限控制的深度陷阱RBAC模型实现时我踩过最深的坑是Spring Security与Vue路由的配合问题。典型症状登录后页面空白控制台报403错误。后端关键配置Configuration EnableWebSecurity public class SecurityConfig { Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf - csrf.disable()) .authorizeHttpRequests(auth - auth .requestMatchers(/api/auth/**).permitAll() .requestMatchers(/api/admin/**).hasRole(ADMIN) .anyRequest().authenticated() ) .sessionManagement(session - session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) ); return http.build(); } }前端路由守卫router.beforeEach((to, from, next) { const publicPages [/login, /register] const authRequired !publicPages.includes(to.path) const loggedIn localStorage.getItem(token) if (authRequired !loggedIn) { return next(/login) } // 检查路由元信息中的权限 if (to.meta.roles !hasPermission(loggedIn, to.meta.roles)) { return next(/403) } next() })关键点后端返回的权限列表要包含前端路由对应的权限标识建议用树形结构组织5. 性能优化实战技巧当商品数据超过1万条时系统开始明显卡顿。这几个优化手段效果立竿见影MyBatis Plus二级缓存配置Configuration MapperScan(com.supermarket.mapper) EnableCaching public class MyBatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 开启二级缓存 interceptor.addInnerInterceptor(new CacheInnerInterceptor()); return interceptor; } }Vue组件懒加载方案const CommodityList () import(./views/commodity/List.vue) const CommodityDetail () import(./views/commodity/Detail.vue)MySQL连接池优化参数spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 idle-timeout: 30000 max-lifetime: 1800000 connection-timeout: 30000 pool-name: SupermarketHikariCP6. 调试与排错实战手册遇到诡异bug时这几个工具组合能救命后端调试三件套# 查看完整SQL日志 logging.level.org.hibernate.SQLDEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinderTRACE # 启用Actuator健康检查 management.endpoints.web.exposure.includehealth,info,metrics前端性能分析// main.js中添加性能监控 Vue.config.performance process.env.NODE_ENV ! production数据库慢查询日志-- MySQL配置 SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1; SET GLOBAL slow_query_log_file /var/log/mysql/mysql-slow.log;最后说个真实案例有次所有商品图片突然无法加载查了3小时发现是Nginx配置里忘了加这个location /uploads/ { alias /path/to/upload/folder/; autoindex off; }