拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Spring Boot实战:构建小区团购管理系统的核心技术解析

简介这是一套面向Java初学者与毕业设计学生的小区团购管理系统实战项目源码基于SpringBoot后端框架与Vue前端技术栈构建解决社区场景下商品发布、订单管理、用户协同采购等核心业务需求。资源包含826个文件涵盖122个Java后端逻辑类、62个Vue组件页面、160个JS交互脚本、79个GIF动效素材及35个JPG/PNG图片资源辅以MySQL数据库脚本与MyBatisPlus持久层配置整体压缩包大小为25.55MB。目录结构完整呈现从绪论、技术选型、系统分析、数据库设计到各模块实现的全流程含用户信息管理、图片/视频素材上传等关键功能代码。已有63人学习下载适合用于课程设计、毕设开发或SpringBootVue全栈能力训练可直接运行调试并快速理解B/S架构下团购系统的典型分层设计与前后端联调逻辑。1. 项目概述从零到一构建一个小区团购管理系统最近几年社区团购的模式可以说是遍地开花尤其是在一些大型社区里由热心业主或团长牵头组织的团购解决了大家日常采购的不少痛点。但随之而来的问题也很明显订单统计靠接龙、收款对账靠手动、商品信息更新不及时团长们常常忙得焦头烂额效率低下还容易出错。作为一个有多年Java后端开发经验的从业者我意识到是时候用技术手段来解放这些“民间团长”的生产力了。于是我决定动手设计并实现一个轻量级、易部署、功能完备的小区团购管理系统。这个项目的核心目标很明确为小区内的团购活动提供一个数字化的管理平台。它需要覆盖从商品上架、订单收集、支付对账到配送核销的全流程同时兼顾团长管理员和普通住户用户两种角色的使用体验。在技术选型上我毫不犹豫地选择了Java Spring Boot这套经典组合。Spring Boot的“约定大于配置”理念和快速启动能力能让我们把精力集中在业务逻辑的开发上而不是繁琐的框架整合。配合MyBatis-Plus、Redis、MySQL这些成熟的技术栈可以快速构建出一个稳定、可扩展的后端服务。这个系统不仅仅是CRUD的简单堆砌它涉及到一些典型的电商业务场景比如库存的并发控制、订单状态的流转、微信支付或支付宝的集成、以及基于角色的权限管理。接下来我将从整体设计、核心模块实现、踩坑实录以及部署上线这几个方面为你完整拆解这个项目的构建过程。无论你是想学习Spring Boot实战还是正打算为你的小区开发一个类似的管理工具相信这篇详尽的记录都能给你带来直接的参考价值。2. 系统整体架构与核心设计思路在动手写代码之前合理的架构设计是保证项目后期可维护、可扩展的关键。对于这个小区团购系统我采用了经典的分层架构和前后端分离模式后端提供RESTful API前端可以是Vue、React或小程序负责展示和交互。这样做的最大好处是职责清晰前后端开发可以并行也便于未来多端适配比如同时开发Web管理端和住户用的小程序。2.1 技术栈选型与考量为什么是这套技术栈每一个选择背后都有其实际考量。后端框架Spring Boot 2.7.x。这是Java领域微服务开发的事实标准。它内嵌了Tomcat服务器通过Starter依赖能一键集成绝大多数常用组件如数据库、缓存、安全等。我选择2.7.x这个长期支持版本是因为它足够稳定社区资源丰富避免了使用最新版本可能遇到的未知坑。持久层MyBatis-Plus MySQL。MyBatis-Plus在MyBatis的基础上做了大量增强提供了通用的Mapper和Service能极大减少单表CRUD的代码量。对于团购系统里大量的商品、订单、用户数据关系型数据库MySQL是可靠的选择。同时使用MyBatis-Plus的乐观锁插件能优雅地处理库存扣减这类并发问题。缓存Redis。主要用于两类场景一是缓存热点数据如首页的商品列表、分类信息减轻数据库压力二是存储用户登录的Token采用JWT方案时可以将Token加入黑名单或存储额外信息以及用作分布式锁确保在高并发下单时库存扣减的准确性。权限安全Spring Security JWT。Spring Security提供了强大且灵活的安全框架。结合JWTJSON Web Token实现无状态的认证授权是当前主流。用户登录后后端生成一个包含其身份和权限信息的Token前端在后续请求中携带后端验证Token有效性并解析出用户信息无需在服务端保存会话。其他工具Lombok通过注解自动生成Getter/Setter、构造方法等让实体类代码更简洁。Hutool一个Java工具类库提供了很多实用的方法比如日期处理、加密解密、HTTP客户端等能避免重复造轮子。Swagger/knife4j自动生成API文档前后端联调和测试时非常方便。注意技术选型没有绝对的好坏只有是否适合当前场景。对于小区团购这种量级这套技术栈在开发效率、运行性能和团队学习成本上取得了很好的平衡。如果预估并发量极高可以考虑引入Spring Cloud Alibaba套件做微服务拆分但初期务必避免过度设计。2.2 核心业务模块划分根据业务流程我将系统后端划分为以下几个核心模块每个模块对应一个代码包package职责单一用户模块 (user)负责住户的注册、登录、个人信息管理。这里区分了普通用户和团长管理员团长拥有额外的管理权限。商品模块 (product)涵盖商品分类、商品信息的增删改查、商品上下架、库存管理。商品信息包括标题、图片、规格、价格、起团数量等。团购活动模块 (campaign)一次团购可以看作一个活动。它关联了具体的商品并设置了活动开始时间、结束时间、成团条件如最少参团人数等。这是整个系统的核心驱动单元。订单模块 (order)用户参与团购即生成订单。这是最复杂的模块之一涉及订单创建、支付集成第三方支付、取消、退款、发货、确认收货等完整的状态流转。购物车模块 (cart)虽然团购有时是直接下单但提供一个购物车功能能让用户体验更好支持批量下单。地址模块 (address)用户管理自己的收货地址。权限与安全模块 (security)集成Spring Security和JWT处理登录认证、接口权限拦截。公用模块 (common)存放全局配置、工具类、统一返回结果封装、异常处理、常量定义等。这种模块化划分使得代码结构清晰便于团队协作和后续的功能迭代。例如当需要增加一个“拼团提醒”功能时可以很明确地在campaign模块下进行扩展。3. 数据库设计与关键表结构解析数据库设计是系统的基石设计得好后期开发事半功倍。我遵循了第三范式的基本理念同时针对性能做了适当的反范式设计如冗余字段。以下是几个核心表的设计思路3.1 用户表 (sys_user)这张表存储所有系统用户包括普通住户和团长。通过一个user_type字段来区分角色如0-普通用户1-团长/管理员。密码存储务必使用加密算法如BCrypt进行哈希处理绝对不要明文存储。CREATE TABLE sys_user ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键, username varchar(50) NOT NULL COMMENT 用户名如手机号, password varchar(100) NOT NULL COMMENT 加密后的密码, nickname varchar(50) DEFAULT NULL COMMENT 用户昵称, avatar varchar(255) DEFAULT NULL COMMENT 头像URL, phone varchar(20) DEFAULT NULL COMMENT 手机号, user_type tinyint(4) NOT NULL DEFAULT 0 COMMENT 用户类型0-普通用户1-团长, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 状态0-禁用1-正常, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username), KEY idx_phone (phone) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;3.2 商品表 (product) 与商品分类表 (product_category)商品分类表是一个树形结构支持多级分类如水果-进口水果-车厘子。商品表则关联分类并包含丰富的商品属性。CREATE TABLE product ( id bigint(20) NOT NULL AUTO_INCREMENT, category_id bigint(20) NOT NULL COMMENT 分类ID, name varchar(200) NOT NULL COMMENT 商品名称, sub_title varchar(500) DEFAULT NULL COMMENT 商品副标题, main_image varchar(500) DEFAULT NULL COMMENT 主图, sub_images text COMMENT 子图JSON数组, detail text COMMENT 商品详情富文本, specs json DEFAULT NULL COMMENT 规格JSON如[{key:重量,value:5kg},{key:产地,value:智利}], price decimal(10,2) NOT NULL COMMENT 单价, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 状态0-下架1-上架, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category_status (category_id,status), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;实操心得specs字段使用MySQL的JSON类型存储商品规格非常灵活前端解析也方便。sub_images字段存储图片URL的JSON数组避免了为商品图片单独建表简化了查询。但要注意JSON字段的索引和查询效率问题如果规格查询条件非常复杂可能需要考虑更结构化的设计。3.3 团购活动表 (campaign)这是连接商品和订单的桥梁是业务的核心。CREATE TABLE campaign ( id bigint(20) NOT NULL AUTO_INCREMENT, product_id bigint(20) NOT NULL COMMENT 商品ID, title varchar(200) NOT NULL COMMENT 活动标题, start_time datetime NOT NULL COMMENT 开始时间, end_time datetime NOT NULL COMMENT 结束时间, group_size int(11) NOT NULL COMMENT 成团人数要求, current_size int(11) NOT NULL DEFAULT 0 COMMENT 当前参团人数, price decimal(10,2) NOT NULL COMMENT 团购价, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-未开始1-进行中2-已结束(成功)3-已结束(失败), create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_product_time (product_id,start_time,end_time), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT团购活动表;状态流转逻辑一个定时任务可以使用Spring的Scheduled注解会定期扫描此表根据当前时间和start_time、end_time以及current_size与group_size的对比自动更新status字段。例如时间到了start_time状态从0变为1时间过了end_time如果current_size group_size状态变为2成功否则变为3失败。3.4 订单表 (order) 与订单明细表 (order_item)考虑到一个订单可能包含多个商品虽然团购常见是单商品但设计上预留扩展性我采用了主-明细结构。订单表记录订单总览订单明细表记录具体商品。CREATE TABLE order ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 订单ID, order_no varchar(32) NOT NULL COMMENT 订单号唯一业务生成, user_id bigint(20) NOT NULL COMMENT 用户ID, campaign_id bigint(20) DEFAULT NULL COMMENT 参与的团购活动ID, total_amount decimal(10,2) NOT NULL COMMENT 订单总金额, pay_amount decimal(10,2) NOT NULL COMMENT 实际支付金额, pay_type tinyint(4) DEFAULT NULL COMMENT 支付方式1-微信2-支付宝, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 订单状态0-待支付1-已支付2-已发货3-已完成4-已取消5-退款中6-已退款, delivery_info json DEFAULT NULL COMMENT 配送信息JSON包含收货人、电话、地址等, pay_time datetime DEFAULT NULL COMMENT 支付时间, delivery_time datetime DEFAULT NULL COMMENT 发货时间, end_time datetime DEFAULT NULL COMMENT 交易完成时间, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_status (user_id,status), KEY idx_campaign (campaign_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;订单号生成策略这是一个容易忽略的细节。我采用的方案是年月日时分秒6位随机数用户ID后4位例如202405201430259876541234。这样既保证了唯一性又一定程度上包含了时间信息和用户信息排查问题时比较方便。可以使用Hutool的IdUtil或自定义工具类生成。4. 核心业务逻辑实现与代码详解有了清晰的数据结构接下来就是实现核心业务逻辑。我将挑几个最具代表性的功能点结合代码讲解其中的关键技术和避坑点。4.1 用户认证与JWT集成首先在pom.xml中引入Spring Security和JWT相关依赖。dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId version0.11.5/version scoperuntime/scope /artifactId然后创建一个JwtUtil工具类负责Token的生成和解析。Component public class JwtUtil { Value(${jwt.secret}) // 从配置文件中读取密钥 private String secret; Value(${jwt.expiration}) // Token有效期如 7天 private Long expiration; // 生成Token public String generateToken(String username, Long userId, Integer userType) { MapString, Object claims new HashMap(); claims.put(userId, userId); claims.put(userType, userType); return Jwts.builder() .setClaims(claims) .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() expiration * 1000)) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } // 从Token中解析用户名 public String getUsernameFromToken(String token) { return getClaimsFromToken(token).getSubject(); } // ... 其他解析方法如解析userId, userType // 验证Token是否有效 public Boolean validateToken(String token, UserDetails userDetails) { final String username getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) !isTokenExpired(token)); } private Boolean isTokenExpired(String token) { final Date expiration getExpirationDateFromToken(token); return expiration.before(new Date()); } }接着需要配置Spring Security。我创建了一个SecurityConfig类继承WebSecurityConfigurerAdapterSpring Boot 2.7.x仍支持或实现SecurityFilterChainBeanSpring Security 5.7推荐方式。这里展示后一种更现代的方式Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // 禁用CSRF因为我们是前后端分离使用JWT无状态认证 .csrf().disable() // 设置会话管理为无状态 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() // 配置请求授权规则 .authorizeRequests() .antMatchers(/api/auth/login, /api/auth/register, /swagger-ui/**, /v3/api-docs/**).permitAll() // 登录注册和API文档放行 .antMatchers(/api/admin/**).hasRole(ADMIN) // 管理员接口需要ADMIN角色 .anyRequest().authenticated() // 其他所有请求都需要认证 .and() // 添加我们自定义的JWT过滤器 .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 处理异常如未认证、权限不足 .exceptionHandling() .authenticationEntryPoint(new JwtAuthenticationEntryPoint()) .accessDeniedHandler(new JwtAccessDeniedHandler()); return http.build(); } Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } // 密码加密器 Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }自定义的JwtAuthenticationFilter会拦截所有请求从Header中提取Token并进行验证如果有效则将用户信息设置到Spring Security的上下文中供后续业务逻辑使用。踩坑实录务必在Spring Security配置中放行Swagger相关的路径/swagger-ui/**,/v3/api-docs/**否则本地调试时连API文档都打不开。另外JwtAuthenticationEntryPoint和JwtAccessDeniedHandler需要自定义以返回统一的JSON格式错误信息而不是默认的登录页或403页面。4.2 团购下单与库存并发控制这是整个系统最核心、也最容易出问题的业务。用户下单时需要检查活动是否进行中、库存是否充足然后扣减库存、创建订单。在高并发场景下多个用户同时购买最后一件商品会导致“超卖”。方案一数据库乐观锁在商品表product中增加一个版本号字段version。更新库存时带上版本号作为条件。// Product实体类 public class Product { private Long id; private String name; private Integer stock; private Integer version; // 版本号 // ... getters and setters } // Service层更新库存方法 Transactional public boolean reduceStock(Long productId, Integer quantity) { Product product productMapper.selectById(productId); if (product null || product.getStock() quantity) { throw new BusinessException(商品不存在或库存不足); } // 使用MyBatis-Plus的UpdateWrapper在更新时检查版本号 UpdateWrapperProduct updateWrapper new UpdateWrapper(); updateWrapper.eq(id, productId) .eq(version, product.getVersion()) // 乐观锁核心版本号必须匹配 .setSql(stock stock - quantity , version version 1); int rows productMapper.update(null, updateWrapper); return rows 0; // 如果rows0说明版本号不匹配更新失败被其他线程抢先修改了 }在订单创建逻辑中调用reduceStock如果返回false则抛出“库存更新失败请重试”的异常提示用户重新下单。方案二Redis分布式锁对于秒杀级别的超高并发数据库乐观锁可能压力较大。可以使用Redis的SETNX命令或Redisson客户端实现分布式锁确保同一时间只有一个线程能执行扣减库存的核心逻辑。public boolean reduceStockWithRedisLock(Long productId, Integer quantity) { String lockKey product_lock: productId; String requestId UUID.randomUUID().toString(); // 唯一标识本次请求用于安全释放锁 try { // 尝试获取锁设置过期时间防止死锁 Boolean locked redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, 10, TimeUnit.SECONDS); if (Boolean.TRUE.equals(locked)) { // 获取锁成功执行库存扣减 Product product productMapper.selectById(productId); if (product.getStock() quantity) { return false; } // 扣减库存这里可以不用乐观锁因为锁保证了串行化 product.setStock(product.getStock() - quantity); productMapper.updateById(product); return true; } else { // 获取锁失败稍后重试或直接返回失败 return false; } } finally { // 释放锁确保是同一个请求释放的避免误删其他请求的锁 if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) { redisTemplate.delete(lockKey); } } }实操心得对于小区团购这种场景并发量通常不会达到秒杀级别使用数据库乐观锁是简单有效的首选方案代码清晰对数据库压力也相对可控。如果真遇到极端情况再考虑引入Redis分布式锁。但无论用哪种方案一定要在业务层给用户友好的提示比如“当前购买人数过多请稍后再试”而不是直接抛出晦涩的异常。4.3 微信支付集成与回调处理集成第三方支付是电商系统的标配。以微信支付JSAPI用于小程序或公众号H5支付为例步骤大致如下配置商户信息在application.yml中配置商户号mchid、API密钥apiV3Key、证书路径等。统一下单用户提交订单后后端调用微信支付统一下单接口生成预支付交易会话标识prepay_id。返回支付参数将prepay_id及其他必要参数如时间戳、随机串、签名按照前端要求小程序或H5的格式组装好返回给前端。前端调起支付前端使用返回的参数调起微信支付界面。处理支付回调用户支付成功后微信服务器会异步通知我们的后端一个特定的回调URL。这是最关键也是最容易出错的一步。支付回调接口的实现要点验证签名必须使用微信支付提供的证书和算法验证回调请求的签名确保请求来自微信官方防止伪造支付成功通知。处理幂等性同一个支付订单微信可能会多次发送回调。我们的接口必须保证即使收到重复通知业务逻辑也只执行一次比如只将订单状态从“待支付”改为“已支付”一次。可以通过在数据库中记录微信支付订单号transaction_id或使用Redis记录已处理的通知ID来实现。异步处理验证签名和幂等性检查通过后应尽快返回SUCCESS的XML响应给微信然后通过消息队列或异步线程去执行后续耗时的业务逻辑如更新订单状态、发送支付成功通知等避免因业务处理超时导致微信认为回调失败而重复通知。PostMapping(/wxpay/notify) public String wxPayNotify(HttpServletRequest request) throws Exception { // 1. 获取请求体微信发送的XML数据 String body HttpUtils.readData(request); // 2. 将XML转换为Map并验证签名此处省略具体验签代码需使用微信支付SDK MapString, String notifyMap WxPayUtil.xmlToMap(body); boolean signatureValid wxPayService.isSignatureValid(notifyMap); if (!signatureValid) { return WxPayUtil.mapToXml(Map.of(return_code, FAIL, return_msg, 签名失败)); } // 3. 处理业务 String orderNo notifyMap.get(out_trade_no); // 我们的商户订单号 String transactionId notifyMap.get(transaction_id); // 微信支付订单号 // 3.1 幂等性检查查询本地订单判断是否已处理过 Order order orderService.getByOrderNo(orderNo); if (order ! null order.getStatus().equals(OrderStatus.PAID.getCode())) { // 订单已支付直接返回成功 return WxPayUtil.mapToXml(Map.of(return_code, SUCCESS, return_msg, OK)); } // 3.2 更新订单状态为已支付记录微信支付单号等 boolean updateSuccess orderService.handlePaySuccess(orderNo, transactionId); if (updateSuccess) { // 3.3 可以在这里触发异步事件如发送短信、更新团购活动参团人数等 eventPublisher.publishEvent(new OrderPaidEvent(this, orderNo)); return WxPayUtil.mapToXml(Map.of(return_code, SUCCESS, return_msg, OK)); } else { return WxPayUtil.mapToXml(Map.of(return_code, FAIL, return_msg, 处理失败)); } }5. 后台管理功能实现要点团长管理员需要一个后台管理界面来管理商品、活动、订单和用户。这里主要讲后端API的设计。5.1 商品与活动管理商品和活动的增删改查是基础功能。需要注意的是上架一个团购活动时必须进行业务校验关联的商品必须存在且已上架。活动的开始时间必须晚于当前时间。活动的结束时间必须晚于开始时间。团购价不能高于商品原价除非有特殊逻辑。如果活动进行中或已结束则不允许修改核心信息如价格、成团人数只能修改一些补充信息或提前结束活动。对于列表查询通常需要支持分页、按名称搜索、按状态筛选等。使用MyBatis-Plus的Page对象和QueryWrapper可以轻松实现。GetMapping(/admin/campaign/list) public ApiResultPageCampaignVO listCampaign(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String keyword, RequestParam(required false) Integer status) { PageCampaign page new Page(pageNum, pageSize); QueryWrapperCampaign queryWrapper new QueryWrapper(); queryWrapper.like(StringUtils.isNotBlank(keyword), title, keyword); queryWrapper.eq(status ! null, status, status); queryWrapper.orderByDesc(create_time); PageCampaign campaignPage campaignService.page(page, queryWrapper); // 将Campaign Page 转换为 CampaignVO PageVO中可能包含商品名称等关联信息 PageCampaignVO voPage convertToVOPage(campaignPage); return ApiResult.success(voPage); }5.2 订单管理与状态流转后台需要能看到所有订单并支持按订单号、用户、状态等多维度筛选。更重要的功能是订单状态的强制操作比如发货输入物流单号将订单状态从“已支付”改为“已发货”。取消订单对于未支付的订单可以手动关闭对于已支付的订单需要走退款流程。处理退款对接微信/支付宝的退款接口并在退款成功后更新订单状态。这些操作都需要记录操作日志方便后续追溯。可以设计一张order_operate_log表记录订单ID、操作类型、操作人、操作前状态、操作后状态、备注和时间。6. 系统部署与运维考量开发完成后如何让系统稳定运行起来我推荐使用Docker容器化部署简单高效。6.1 使用Docker Compose一键部署编写一个docker-compose.yml文件定义MySQL、Redis和应用服务。version: 3.8 services: mysql: image: mysql:8.0 container_name: community-mysql environment: MYSQL_ROOT_PASSWORD: your_strong_password MYSQL_DATABASE: community_buy ports: - 3306:3306 volumes: - ./mysql/data:/var/lib/mysql - ./mysql/conf:/etc/mysql/conf.d restart: always redis: image: redis:7-alpine container_name: community-redis ports: - 6379:6379 volumes: - ./redis/data:/data restart: always app: build: . container_name: community-app depends_on: - mysql - redis ports: - 8080:8080 environment: - SPRING_PROFILES_ACTIVEprod - DB_HOSTmysql - REDIS_HOSTredis restart: always然后在项目根目录创建DockerfileFROM openjdk:11-jre-slim VOLUME /tmp ARG JAR_FILEtarget/*.jar COPY ${JAR_FILE} app.jar ENTRYPOINT [java,-jar,/app.jar]在服务器上只需安装好Docker和Docker Compose将项目Jar包和配置文件准备好执行docker-compose up -d整个服务栈就会启动。6.2 配置文件与敏感信息管理切勿将数据库密码、支付密钥等敏感信息硬编码在代码或application.yml中。Spring Boot支持多种配置方式生产环境配置使用application-prod.yml并通过环境变量SPRING_PROFILES_ACTIVEprod激活。敏感信息使用环境变量或专门的配置中心如阿里云ACMSpring Cloud Config。在docker-compose.yml中通过environment传递。# application-prod.yml 示例 spring: datasource: url: jdbc:mysql://${DB_HOST:localhost}:3306/community_buy?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/Shanghai username: ${DB_USER:root} password: ${DB_PASSWORD:} # 从环境变量获取 redis: host: ${REDIS_HOST:localhost} port: 6379 wx: pay: mchid: ${WX_MCHID} apiv3-key: ${WX_API_V3_KEY} # 从环境变量获取6.3 日志与监控日志使用Logback或Log4j2配置合理的日志级别和滚动策略。将日志文件挂载到宿主机便于查看。关键业务操作如支付回调、库存扣减务必记录INFO或WARN级别日志。健康检查Spring Boot Actuator提供了/actuator/health端点可以集成到Docker的健康检查或运维监控平台中。错误报警可以集成Sentinel或SkyWalking进行链路追踪和异常报警。对于小型项目至少应该配置日志文件监控当出现大量ERROR日志时能及时通知。7. 开发与部署过程中的常见问题排查在实际开发和部署中我遇到了不少典型问题这里总结一下希望能帮你避坑。问题现象可能原因排查步骤与解决方案服务启动报DataSource连接失败1. 数据库地址/端口错误。2. 数据库未启动。3. 用户名密码错误。4. 网络不通Docker容器间。1. 检查application.yml配置特别是生产环境配置文件是否激活。2. 使用docker ps或mysql -h host -u user -p手动连接测试。3. 在Docker Compose中确保服务依赖depends_on设置正确但注意它只控制启动顺序不保证数据库已就绪。建议应用启动脚本中加入对数据库的健康检查重试机制。微信支付回调一直收不到或收到但签名验证失败1. 回调URL未在微信商户平台正确配置或未备案。2. 服务器防火墙/安全组未开放对应端口。3. 验签逻辑错误特别是APIv3密钥或证书不对。4. 网络问题导致微信无法访问你的公网回调地址。1. 在微信支付后台仔细检查回调URL确保是https生产环境必须且可公网访问。2. 使用curl或Postman模拟微信回调本地调试验签逻辑。3.务必使用微信支付平台提供的证书工具重新下载证书并确保代码中加载的证书路径正确。APIv3密钥和之前的API密钥不同。下单时出现“库存超卖”1. 未做并发控制。2. 乐观锁更新失败后未给用户明确提示。3. 缓存与数据库库存不一致。1. 确保扣减库存的操作是原子性的使用4.2节提到的乐观锁或分布式锁。2. 在Service层捕获乐观锁更新失败异常返回明确的业务错误信息如“库存不足请重新下单”。3. 如果使用了Redis缓存商品库存需要保证缓存和数据库的双写一致性更新数据库后要删除或更新缓存。前端请求API返回403或4011. 请求未携带Token或Token已过期。2. Token格式错误。3. 接口路径被Spring Security拦截但用户角色权限不足。1. 检查前端请求头Authorization是否正确格式Bearer your_jwt_token。2. 在JwtAuthenticationFilter中打印Token解析日志看是否抛出异常。3. 检查SecurityConfig中的权限配置antMatchers().hasRole()是否与用户实际角色匹配。使用MyBatis-Plus查询结果字段为null1. 实体类属性名与数据库字段名未正确映射下划线转驼峰默认开启但特殊名称可能不对。2. 查询时未指定要查询的列默认查询所有但可能有关联字段未在SQL中体现。1. 在实体类字段上使用TableField注解指定数据库列名如TableField(user_type)。2. 检查是否使用了TableName注解指定表名。3. 对于复杂的联表查询建议使用自定义的XML映射文件或QueryWrapper手动构建查询SQL。最后再分享一个部署时的小技巧在docker-compose.yml中为应用服务添加一个healthcheck配置让Compose能判断应用是否真正启动成功这比单纯的depends_on更可靠。app: build: . ... healthcheck: test: [CMD, curl, -f, http://localhost:8080/actuator/health] interval: 30s timeout: 10s retries: 3 start_period: 40s这个项目从设计到实现再到部署上线几乎涵盖了中小型Java Web项目的全流程。过程中最大的体会是清晰的业务边界划分和稳健的并发处理是后端系统的生命线。不要急于堆砌功能先把核心链路用户-商品-活动-订单-支付跑通、跑稳。这个系统完全可以作为Spring Boot的进阶练手项目其中涉及的JWT认证、乐观锁、支付集成、Docker部署等都是非常实用的技能点。你可以根据自己小区的实际需求在此基础上增加更多功能比如拼团提醒、团长佣金统计、财务报表导出等让它真正成为一个好用、耐用的社区工具。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门