多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Java微信小程序商城开发:从后端骨架到支付闭环的完整实践

Java微信小程序商城开发:从后端骨架到支付闭环的完整实践 简介面向中小电商及个人开发者该JAVA微信小程序商城源码附带完整后台基于Spring MVC、MyBatis、Spring、Maven及MySQL架构前端以HTML5与CSS3构建后台管理界面采用Bootstrap Ace框架功能涵盖商品发布、物流管理、评价系统、优惠券发放、运费规则、在线客服、在线支付与退款并集成微信管理相关能力是一套可直接投入二次开发的微信商城小程序解决方案。压缩包约20.5MB内容围绕商城核心业务组织适合具备Java基础的学习者研读代码结构与前后端交互逻辑也可作为毕业设计或商业项目的基础模板。通过这套源码读者可掌握从商品上架、购物车、订单处理到支付退款、物流跟踪及客户评价的完整电商闭环同时理解Spring MVC与MyBatis在真实项目中的整合方式。目前已有5047人浏览学习资源热度较好对希望快速搭建微信商城或提升Java Web实战能力的人群具有参考价值。1. 一套能跑起来的 Java 微信小程序商城值不值得自己攒如果你搜过“JAVA微信小程序商城源码完整后台”大概率见过两种东西一种是只给前端页面、后端是个空壳的演示项目另一种是代码堆得密密麻麻、一跑起来全是报错的半成品。真正能用的“完整后台”指的是管理员能登录、能改商品、能看订单、能管用户而不是打开数据库手动改几条记录就号称后台管理。这套组合的落地难度并不在“写个接口”或“画个页面”而在于把微信生态的登录态、支付回调、订单状态机和后台的商品上架流程串成一条线。对个人开发者来说它是完整走通一次前后端联调的绝佳素材对小型团队来说它是从零开发一套带管理后台的电商系统的最短路径。后端选 Java 意味着你可以依赖 Spring Boot 那一整套成熟的生态不必在基础设施上浪费精力。本文会按照“后端骨架 → 小程序端 → 管理后台 → 订单支付 → 避坑”的顺序把这套系统拆开讲清楚。你能看到具体的表结构设计、可运行的代码片段、必须调的参数以及那些文档里不写、只有跑过才会懂的坑。2. 技术选型与后端骨架先搞清楚这套源码由哪几块拼起来2.1 小程序商城为什么默认选 Spring Boot MyBatis-Plus市面上 Java 系的电商后台十套里有八套是 Spring Boot 打底这不是巧合。微信小程序的接口风格是典型的 RESTful JSONSpring Boot 的 Controller 层天生就是干这个的一个RestController加几个注解就能把实体类直接序列化成前端要的格式。另一大优势是生态里现成的轮子多要做登录鉴权有 Sa-Token、Shiro、Spring Security要做缓存有 Redis Starter要做定时任务有 XXL-Job 或者自带的Scheduled几乎不需要自己造工具。持久层我建议选 MyBatis-Plus 而不是纯 MyBatis。商城系统的查询场景非常琐碎商品要分页、订单要按状态筛、后台要根据关键词搜这些如果用纯 MyBatis每个方法都要手写 XML 和动态 SQL工作量直接翻倍。MyBatis-Plus 的Wrapper构造器能覆盖 80% 的日常查询剩下的复杂统计再用注解 SQL 补齐效率高很多。数据库选 MySQL 就够了表结构是关键。商城系统最核心的几张表是product商品、product_sku规格库存、order订单、order_item订单明细、user微信用户、cart购物车、category分类。注意订单表千万别叫order因为order是 SQL 关键字到时候写原生 SQL 全得加反引号纯属给自己挖坑。2.2 项目目录结构与启动流程拿到源码后第一步做什么一套规整的商城后端目录结构应该一眼就能看出分层。我习惯这样组织mall-api ├── controller # 接口层只做参数接收和结果返回 ├── service # 业务层写核心逻辑 ├── mapper # 数据访问层继承 BaseMapper ├── entity # 数据库实体类 ├── dto # 前端传参的封装对象 ├── vo # 返回给前端的视图对象 ├── config # 配置类如拦截器、跨域、Redis ├── common # 统一返回结果、异常处理、工具类 └── utils # JWT、MD5、金额计算等工具拿到源码后不要急着启动先改三个地方。第一是application.yml里的数据库连接把 URL、用户名、密码换成你自己的第二是 Redis 的地址和密码登录态和缓存都会用到第三是小程序的appid和secret这两个值从微信公众平台的开发设置里拿。启动时最容易出错的是端口冲突和 Redis 未启动。后端默认跑在 8080如果你本机的 8080 被占了在配置里改成 8081 就行。Redis 如果没有现成的Windows 用户可以用 Memurai 这类兼容工具Mac 用户直接brew install redis启动后确认ping能返回PONG再跑后端不然启动过程不会报错但登录接口一调用就会超时。2.3 统一返回结果与异常处理前后端联调不吵架的基础前端拿到后端接口最怕的就是有时候返回{code:0, data:{...}}有时候又返回{success:true, result:{...}}字段名都对不上根本没法写。所以一上来就要定死一套统一返回格式。我常用的结构是Data public class ResultT { private Integer code; // 0 表示成功非 0 表示业务异常 private String msg; // 提示信息直接展示给用户 private T data; // 业务数据 public static T ResultT success(T data) { ResultT result new Result(); result.setCode(0); result.setMsg(success); result.setData(data); return result; } public static T ResultT error(String msg) { ResultT result new Result(); result.setCode(500); result.setMsg(msg); return result; } }code字段用 0 表示成功、非 0 表示失败比 HTTP 状态码更实用。原因很简单HTTP 200 并不代表业务成功比如“库存不足”这种提示接口状态码照样是 200但业务上应该是一个明确的失败码。前端通过code判断逻辑通过msg直接弹提示两边约定清楚联调效率能提升一大截。全局异常处理也是必须提前做的。用RestControllerAdvice捕获业务异常、参数校验异常和兜底异常否则一旦代码里有个空指针前端拿到的就是一坨堆栈信息没法解析。常见的做法是自定义一个BizException业务代码里手动抛全局处理器统一转换成Result.error(msg)返回。3. 微信小程序端登录、首页与商品列表的落地实现3.1 微信登录的完整闭环code 换 openid 的每一步小程序端的登录不是传统的“用户名密码”而是基于微信的wx.login()。核心思路是小程序端调用wx.login()拿到一个临时凭证code把这个code传给后端后端拿着它去微信的接口换openid用户唯一标识和session_key。后端的核心逻辑是这样PostMapping(/login) public ResultString login(RequestBody LoginDTO dto) { // 1. 拿着 code 向微信服务器换 openid 和 session_key String url https://api.weixin.qq.com/sns/jscode2session?appid appid secret secret js_code dto.getCode() grant_typeauthorization_code; String result restTemplate.getForObject(url, String.class); JSONObject json JSONObject.parseObject(result); String openid json.getString(openid); if (openid null) { return Result.error(登录失败请重试); } // 2. 查询用户是否存在不存在则自动注册 User user userMapper.selectOne(new LambdaQueryWrapperUser() .eq(User::getOpenid, openid)); if (user null) { user new User(); user.setOpenid(openid); user.setCreateTime(LocalDateTime.now()); userMapper.insert(user); } // 3. 生成 token 返回给前端后续请求带上即可 String token jwtUtil.generateToken(user.getId()); return Result.success(token); }code是一次性的有效期只有 5 分钟而且只能使用一次所以前端不要缓存它。换取的session_key不要返还给前端它用于解密手机号等敏感信息留在后端即可。这里要注意访问微信接口时依赖的restTemplate需要配置好超时时间我一般设置为连接超时 3 秒、读取超时 5 秒因为一旦微信接口响应慢会拖垮整个登录接口的响应时间用户端表现就是“转圈半天进不去”。token 我用的是 JWT里面只存用户 ID不存敏感信息。生成后设置 7 天有效期前端每次请求时放到Authorization请求头里后端用一个拦截器统一校验校验通过后把用户 ID 放入ThreadLocal这样后续业务代码里直接CurrentUser.getUserId()就能拿到当前用户不用每次从 token 里解析。3.2 商城首页与商品列表接口设计决定前端省不省事首页要展示的东西比较多轮播图、分类导航、推荐商品。如果你把这三块拆成三个接口前端就要发起三次请求体验不好。我一般会做一个聚合接口把首页需要的数据一次返回。商品列表接口的设计要更讲究一点。小程序端的商品列表页通常有分类筛选、关键词搜索、价格排序、分页加载。这个接口别整太复杂前端传page和size后端返回总条数和当前页数据即可。排序用sort字段控制default按创建时间倒序、priceAsc按价格升序、priceDesc按价格降序。前端点击排序按钮时切换并重新请求第一页数据。这里推荐用 MyBatis-Plus 的分页插件GetMapping(/list) public ResultPageProductVO list(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer size, RequestParam(required false) Long categoryId, RequestParam(required false) String keyword, RequestParam(defaultValue default) String sort) { PageProduct pageParam new Page(page, size); LambdaQueryWrapperProduct wrapper new LambdaQueryWrapper(); wrapper.eq(categoryId ! null, Product::getCategoryId, categoryId) .like(StringUtils.isNotBlank(keyword), Product::getProductName, keyword) .eq(Product::getStatus, 1); // 只展示上架中的商品 // 排序处理 if (priceAsc.equals(sort)) { wrapper.orderByAsc(Product::getPrice); } else if (priceDesc.equals(sort)) { wrapper.orderByDesc(Product::getPrice); } else { wrapper.orderByDesc(Product::getCreateTime); } PageProduct result productMapper.selectPage(pageParam, wrapper); return Result.success(result); }注意eq和like方法前面的条件判断categoryId ! null才拼接分类条件keyword非空才拼接搜索条件。这是 MyBatis-Plus 最实用的地方直接避免了“手动拼 SQL 少加一个空格”的尴尬。另一个细节是status字段必须过滤不然后台下架的商品会照样展示在小程序里。商品价格存储建议用Integer类型单位是“分”而不是BigDecimal。原因有两点一是BigDecimal在 JSON 序列化时容易出精度问题前端拿到 99.9 和 99.90 会显示不一致二是涉及订单金额计算、微信支付时单位就是分直接用Integer可以少做一次单位转换还能避免浮点运算误差。3.3 前端页面的正确姿势原生框架还是 uni-app小程序端的选择上常见的有原生开发、uni-app 和 Taro 三种。原生开发的好处是调试最直接、没有框架层转换的 Bug适合只做微信端的场景。但如果你后期想做抖音小程序、支付宝小程序uni-app 是更经济的选择一套代码多端复用。无论选哪种页面层级都一样index首页、category分类、cart购物车、user个人中心四个 tab加上goods_list商品列表、goods_detail商品详情、order_confirm确认订单等二级页面。购物车和个人中心都需要登录态要记得在onShow生命周期里检查 token没有 token 就跳授权页。4. 完整后台的核心模块权限、商品管理和订单状态流转4.1 后台权限模型为什么不用 Spring Security 而用 Sa-Token后台系统最基础的能力是管理员登录和权限控制。常见的方案有 Spring Security JWT 和 Sa-Token 两种。Spring Security 功能强大但配置繁琐官网文档也绕来绕去很多新手光配一个“放行哪些路径、拦截哪些路径”都要折腾半天。Sa-Token 就好比是“轻量版 Shiro”开箱即用一句话就能完成登录拦截// 登录成功后的处理 StpUtil.login(adminId); // 创建登录态 String tokenValue StpUtil.getTokenValue(); // 获取 token 给前端后续每个需要鉴权的接口只需要加一行注解SaCheckPermission(product:add)就能控制这个接口必须有“新增商品”权限的管理员才能调用。Sa-Token 还内置了踢人下线、账号封禁、会话管理这些能力这些功能如果用 Spring Security 自己写没个几百行代码下不来。权限模型采用经典的 RBAC管理员表admin、角色表role、菜单权限表permission以及管理员-角色、角色-权限两张关联表。初期不用做太细配到“菜单级”就行也就是控制谁能进商品管理、谁能看订单列表、谁能操作退款不需要控制到“按钮级”。等系统真的跑起来了、运营团队变大了再往细粒度拆也不迟。4.2 商品上架与 SKU 管理一张表还是两张表电商系统的商品设计核心是 SPU 和 SKU 的区分。SPU 是“商品”的概念比如“iPhone 15 Pro”SKU 是“具体规格”的概念比如“iPhone 15 Pro 256GB 黑色”。一件 SPU 下可以挂多个 SKU每个 SKU 有自己的库存、价格和图片。表结构上建议用两张表否则会出现大量冗余字段比如同一个商品的不同颜色在商品表里要重复多条记录分类、详情、图片全都一样只区别在一个颜色值。更麻烦的是后台编辑商品时如果只改标题要连带更新所有规格行数据一致性很难保证。后端接口建议这样设计一次性提交整棵商品树PostMapping(/save) public ResultString save(RequestBody ProductSaveDTO dto) { // 1. 插入 SPU 到 product 表 Product product new Product(); BeanUtils.copyProperties(dto, product); product.setStatus(0); // 默认下架状态等审核完成再上架 productMapper.insert(product); // 2. 批量插入 SKU 到 product_sku 表 for (SkuDTO sku : dto.getSkuList()) { sku.setProductId(product.getId()); sku.setStock(sku.getStock()); sku.setPrice(sku.getPrice()); skuMapper.insert(sku); } return Result.success(保存成功); }两个关键点。第一商品主表新增时的status必须默认下架等管理员确认所有 SKU 都已录好、库存无误后再点“上架”按钮避免出现“商品已展示但 SKU 还没录完”的情况。第二保存操作要加事务Transactional(rollbackFor Exception.class)否则 SPU 插入成功、SKU 插入时抛异常商品表就会留下一个没有规格的孤儿记录。4.3 订单状态机从待付款到已完成的状态流转控制后台的订单管理本质就是状态流转的管理。电商订单的五种核心状态待付款0、待发货1、待收货2、已完成3、已取消4另外售后状态可以单独拆出去不要在订单主表上叠加太多状态维度。订单状态流转必须靠系统来保证而不是让前端随意传值。一个常见的错误做法是后台管理接口直接接收前端传的status字段然后update order set status ? where id ?这样是能改但业务规则完全失控比如“已完成的订单还能被改成待发货”。正确的做法是每个状态变更对应一个独立接口接口里写清楚校验逻辑PostMapping(/ship) public ResultString ship(RequestParam Long orderId) { Order order orderMapper.selectById(orderId); // 校验当前状态必须是待发货 if (order null || order.getStatus() ! 1) { return Result.error(当前订单状态不支持发货操作); } order.setStatus(2); // 待收货 order.setShipTime(LocalDateTime.now()); // 这里还可以记录操作日志谁在什么时候做的发货 orderMapper.updateById(order); return Result.success(发货成功); }发货、取消、完成每个操作都是这样的套路核心逻辑就是“先查状态、再校验、再更新”。这里切忌写一个通用的updateStatus接口把校验逻辑暴露给前端否则用户在订单详情页抓包修改参数就能把订单状态改成任意值。除了状态流转后台还需要记录关键时间点创建时间、支付时间、发货时间、完成时间这些字段在排查纠纷时非常重要。5. 订单与支付闭环节点正确走通微信支付要过的三关5.1 下单接口的后端姿态库存校验与订单生成的原子性下单是整个链路里对数据一致性要求最高的环节。用户可能瞬间提交多次下单请求如果每次请求都直接减库存库存会变成负数如果不校验库存就会出现超卖后台库存显示有货实际发货时却凑不齐货。下单接口应该遵循“先校验、再锁定、后扣减”的顺序Transactional(rollbackFor Exception.class) public ResultString createOrder(OrderCreateDTO dto) { // 1. 校验商品与库存 for (OrderItemDTO item : dto.getItems()) { ProductSku sku skuMapper.selectById(item.getSkuId()); if (sku null || sku.getStock() item.getCount()) { return Result.error(商品库存不足); } } // 2. 计算订单总额用后端算出来的价格不能信任前端传的价格 Integer totalAmount 0; for (OrderItemDTO item : dto.getItems()) { ProductSku sku skuMapper.selectById(item.getSkuId()); totalAmount sku.getPrice() * item.getCount(); } // 3. 生成订单主表记录 Order order new Order(); order.setUserId(CurrentUser.getUserId()); order.setOrderNo(generateOrderNo()); // 生成唯一的业务订单号 order.setTotalAmount(totalAmount); order.setStatus(0); // 待付款 orderMapper.insert(order); // 4. 扣减库存乐观锁方式 int rows skuMapper.deductStock(dto.getSkuId(), item.getCount()); if (rows 0) { // 影响行数为0说明库存已变 throw new BizException(库存不足请重试); } return Result.success(order.getOrderNo()); }第 4 步的扣库存不能简单写成stock stock - 1要加上条件stock countSQL 大致是UPDATE product_sku SET stock stock - #{count} WHERE id #{skuId} AND stock #{count}这样即使并发请求同时进来数据库的行锁会保证只有一个请求能成功另一个请求影响行数为 0直接被判定为库存不足。价格计算同理永远以后端查出来的数据库价格为基准前端传的价格只能用于展示信前端传过来的价格是电商系统的大忌一旦被抓包改价损失没法追。5.2 微信支付接入的三关统一下单、签名与回调验签支付链路是让最多人翻车的环节。第一步是后端调用微信支付的“统一下单”接口拿回prepay_id。第二步是后端用prepay_id生成支付参数返回给小程序端小程序端用wx.requestPayment调起支付。第三步是用户支付成功后微信服务器异步通知你的回调接口你收到通知后更新订单状态。第一关是签名。调用微信支付接口的所有参数都需要按规则生成签名参数名 ASCII 排序、URL 键值对拼接、最后拼上key做 MD5 或 HMAC-SHA256。这个环节最容易出的问题有两类一是参数名大小写不对二是商户号和证书路径配置错了。签名算法本身只要照着微信支付文档的示例一步一步来基本能过。第二关是回调验签。微信服务器通知你的接口时也会带上签名你必须先用同样的算法验证签名确认这条通知真的来自微信而不是某个闲得无聊的人伪造的请求。验签通过后还要核对out_trade_no商户订单号和total_fee支付金额是否与数据库中的订单一致。第三关是幂等处理。同一个订单微信可能会回调多次如果你每次回调都更新一次订单状态没问题但如果每次回调都给用户加一次余额那就出大事了。所以回调处理必须加判断只有当订单状态为“待付款”时才更新为“待发货”。这个逻辑用一句话总结就是先查订单看状态再处理处理完了无论重复收到多少回调都直接返回成功。6. 避坑指南跑了三套商城源码才总结出的五个高频问题6.1 微信登录接口报 40029code 被重复使用现象前端明明拿到了 code后端拿去换 openid 时却返回{errcode:40029,errmsg:invalid code}。原因wx.login()生成的 code 只能用一次5 分钟内有效。最常见的场景是开发者用调试工具页面onLoad里调了一次wx.login()onShow里又调了一次第二次拿到的 code 去后端换 openid微信那边发现这个 code 已经失效了。另一个原因是前端把code缓存在了全局变量里切页面后再次提交登录就报错。解决每次需要登录时都重新调用wx.login()获取 code不要在本地缓存。后端换到 openid 后立刻把 code 丢掉。调试时如果频繁切换账号导致 40029清理小程序缓存重新编译就能恢复。6.2 小程序真机预览时接口请求失败域名白名单没配现象开发者工具里接口调得通一上真机预览所有请求全部request:fail。原因微信小程序要求所有正式环境请求的域名都必须是 HTTPS而且在微信公众平台配置了合法域名后还要在开发者工具的“详情-域名信息”里同步刷新。最坑的是如果你使用的是 IP 地址加端口号的形式比如http://192.168.1.100:8080微信要求必须备案过的域名本地 IP 在真机上访问不了。解决开发调试阶段在开发者工具里勾选“不校验合法域名”进行真机测试时要么拿一台带公网域名的测试服务器要么用内网穿透工具把本地项目映射到公网域名下。上线前务必保证所有接口都是 HTTPS 的正式域名且已在后台配置。不要抱着侥幸心理去年微信审核对这类问题卡得很严。6.3 支付回调收不到通知回调地址没有公网可访问现象小程序端支付弹窗提示“支付成功”但后台订单状态一直是“待付款”。原因微信支付成功后微信服务器会主动请求你的回调地址。如果你本地开发时配置的回调地址是http://localhost:8080/pay/callback微信服务器根本访问不到你的电脑。就算你用的是内网穿透穿透工具免费版域名经常更换微信那边记录的还是旧地址。解决回调地址配置必须是一个微信服务器能访问到的公网 HTTPS 地址。本地联调阶段用内网穿透但要注意穿透工具的域名稳定性。另外回调接口要在日志里完整记录微信返回的数据。改完回调地址后别急着测试先手动模拟一条支付成功通知的数据用 Postman 直接 POST 到你的回调接口看看业务逻辑是否正常。这是排查支付问题最有效的方式能帮你把“微信配置问题”和“自己代码问题”区分开。6.4 后台修改商品价格不生效Redis 缓存没同步更新现象管理员在后台把商品价格从 99 改成 199小程序端详情页还是显示 99。原因商品详情接口做了缓存第一次请求时把数据放到了 Redis 里设置了较短的有效期。后台改价格只更新了 MySQLRedis 里的旧数据还没过期前端拿到的还是缓存中的旧价格。解决在后台的商品修改接口里更新完数据库后同步删除对应的缓存 key不要只依赖缓存过期。常见的做法是给每个商品一个独立的缓存 key比如product:detail:123后台修改时执行redisTemplate.delete(product:detail: productId)。价格、库存这类敏感数据缓存时间也别设置太长我一般设置 30 分钟并且在缓存里同时保存最后更新时间排查问题时能直观看到数据是哪个时间点的。6.5 多人同时用一个后台账号导致操作混乱缺少登录态互踢策略现象两个管理员用同一账号分别在不同电脑登录A 修改了商品标题B 在另一台电脑上保存时把 A 的改动覆盖了而且两个人都不知道对方在线。原因登录接口只生成了 token没有做同账号互踢处理。Sa-Token 默认的策略是允许同一账号多处登录除非显式配置isConcurrent为 false。解决后台管理系统的账户属于强权限账户建议直接配置登录互踢。在 Sa-Token 里这样处理SaTokenInfo tokenInfo StpUtil.login(adminId, new SaLoginModel() .setIsConcurrent(false) // 同一账号是否允许同时登录 .setIsShare(false)); // 多人登录时是否共享 token这样同一账号新登录时之前的 token 立刻失效。再加一个“最近登录记录”表记录谁在什么时间、什么 IP 登录过后台权限变动或数据异常时能快速追踪到操作者。这一步对商城这种直接涉及资金和商品数据的系统尤其重要别等出事了才发现连操作日志都没有。7. 上线前的验证清单与最后一公里的细节商城系统开发完成不等于能上线从“本地能跑”到“线上可用”之间还有一段路。这段路的核心不是写新功能而是把已有功能当成“黑盒”去验证边界。第一个必测场景是库存并发开两个浏览器窗口同时登录两个账号同一件库存只剩 1 件的商品同时下单系统必须只让一个订单成功。如果你用的是简单的update stock stock - 1而不是带条件的乐观锁更新这个测试大概率会失败。建议写一个小的压测脚本用 JMeter 并发 20 个线程请求下单接口重点看“最终库存是否为负数”和“成功订单数是否大于库存数”这两个指标。第二个必测场景是支付回调的幂等性用 Postman 手动向你的回调接口连发 10 次相同的支付成功通知检查订单状态是否在第一次通知后就不再变化。第三个必测场景是时区和时间显示。小程序展示订单时间时会不会出现“下单时间是 8 小时前”这种诡异问题后端数据库连接串里加上serverTimezoneAsia/ShanghaiRedis 序列化和 JSON 返回都统一用中国时区格式化避免前后端时区差异导致时间错乱。这个坑不显眼但线上用户一眼就能看到。缓存策略上首页的轮播图和推荐位可以设置较长的缓存时间因为这些内容基本一周才改一次。商品详情的库存信息则不适合缓存太久否则用户加了购物车、点结算的瞬间发现库存已经没了体验很不好。日志方面建议至少把以下事件的参数和结果打印到日志里登录、下单、支付回调、后台商品修改、后台订单操作。不需要打印密码和 token 这类敏感信息但订单号、用户 ID、操作内容必须留痕。线上出了问题没有日志的排查就像是在黑匣子里找故障点只能靠猜。我自己在部署这套系统时吃过最大的亏是数据库连接池配置过小。默认的 HikariCP 最大连接数是 10本地开发没问题一旦有几十个人同时访问连接池就满了后端日志里会出现大量connection timeout。记得在application.yml里调大maximum-pool-size一般设置 30 到 50 之间视服务器规格而定。还有一个小习惯上线前全局搜一下printStackTrace和System.out.println这些调试输出留在线上环境里既影响性能又会把异常信息打到控制台而不是日志文件里规范的做法是统一走 SLF4J 的log.error和log.info。这套 Java 微信小程序商城跑通之后后续加秒杀、加优惠券、加分销骨架都是现成的希望能帮到你。本文还有配套的精品资源点击获取
返回列表