
简介这是一套完整的微信小程序购物商城全栈开发项目面向Java后端与小程序前端初学者及课程设计学生解决电商类应用从用户端到管理端的全流程开发实践需求。资源包含可本地编译运行的Java Spring Boot后端、微信小程序前端、MySQL数据库脚本及详细文档说明覆盖商品浏览、购物车管理、订单提交、物流跟踪、评价反馈与后台商品/订单/用户地址管理等核心业务模块。压缩包共1539个文件以176个Java后端逻辑文件、305个JS小程序交互脚本、385个HTML/WXML页面结构文件、219个PNG/GIF商品图及59个CSS样式文件为主辅以SQL建表语句、PDF文档与配置文件整体大小为10.27MB。已有205人学习下载项目经助教审定、评审分达95分以上难度适中目录结构规范模块职责清晰特别适合用于毕业设计参考、实训项目复现或Java小程序技术栈整合学习。1. 微信小程序购物商城Java后端MySQL完整业务闭环为什么它能拿95分这不是一个“套壳Demo”——它跑通了从微信用户扫码登录、商品浏览、加购结算、订单履约到后台管理的全链路。我去年帮三个学生复现这个项目时发现它没用Spring Boot自动装配那一套“黑匣子”而是用原生Servlet MyBatis手写DAO层SQL写在XML里连分页都自己拼LIMIT数据库表设计不玩花活user、product、order、address、comment五张主表加外键约束字段命名直白如order_status TINYINT COMMENT 0待支付 1已支付 2已发货 3已完成 4已取消小程序端用WXMLWXSSJS三层分离没上Wepy或Taro所有API调用都封装在/utils/request.js里连token刷新逻辑都写了注释。适合想搞懂“微信小程序怎么和Java后端真实对接”的人——不是学概念是学怎么让wx.login()返回的code真正在Java里换出openid怎么把wx.chooseAddress()拿到的收货信息存进MySQL怎么让管理员在浏览器里点“发货”按钮后小程序端订单状态实时变蓝。如果你正卡在“小程序能发请求但Java后端收不到参数”或者“MyBatis查出来是null但SQL在Navicat里能跑”这份高分项目就是你的后悔药。2. 项目结构拆解看清Java后端与小程序如何握手2.1 后端工程结构Servlet MyBatis JSP管理后台项目根目录下有src/Java源码、WebContent/前端资源、WEB-INF/web.xml核心配置。注意这不是Spring Boot项目没有pom.xml里的starter全家桶依赖全靠WebContent/WEB-INF/lib/下的jar包撑着——mybatis-3.4.6.jar、mysql-connector-java-5.1.47.jar、jstl-1.2.jar、servlet-api-2.5.jar。web.xml里注册了两个关键ServletLoginServlet处理小程序登录回调OrderServlet处理订单增删改查。所有接口路径统一走/api/xxx比如小程序调https://localhost:8080/api/order/list后端就由OrderServlet的doGet()方法接住。提示别急着改端口。web.xml里url-pattern/api/*/url-pattern决定了所有API必须带/api/前缀小程序端request.js里的baseUrl必须配成http://localhost:8080否则404不是后端问题是路径没对上。2.2 小程序端目录WXML驱动UIJS串联业务小程序工程里pages/下有index/首页、product/商品详情、cart/购物车、order/订单列表、user/个人中心五个页面。每个页面的.js文件里都有onLoad()生命周期函数里面调app.globalData.request({ url: /api/product/list })拉数据。重点看app.js它定义了全局request方法自动在header里塞Authorization: wx.getStorageSync(token)并在fail回调里判断是否err.errMsg.includes(request:fail)——这是处理网络异常的血泪经验微信开发者工具模拟弱网时fail会触发但err.errMsg是字符串不能直接 null。2.3 数据库设计五张表撑起全部业务MySQL建库脚本在/doc/database.sql里共5张表user存微信openid、session_key、昵称、头像没存手机号这是刻意设计登录流程只走wx.login()后续需要手机号再调getPhoneNumberproductprice DECIMAL(10,2)、stock INT、img_url VARCHAR(255)图片路径存相对地址如/upload/product/123.jpgorderuser_id、status、total_price、create_time没冗余商品信息下单时把商品快照存到order_item表order_itemorder_id、product_id、quantity、price_at_order下单时价格防止商品改价影响历史订单addressuser_id、consignee、phone、province/city/district、detail字段名和微信chooseAddress返回字段一一对应注意order_item表的price_at_order是关键设计。我见过太多项目直接存product.price结果老板半夜改价第二天客服接到一堆投诉说“昨天下单299今天显示399”。这个项目用快照思维堵死了漏洞。2.4 接口协议RESTful风格但带微信特色所有API返回JSON格式统一{ code: 200, msg: success, data: { ... } }但登录接口/api/user/login接收的是小程序wx.login()返回的code后端用https://api.weixin.qq.com/sns/jscode2session换openid不走JWT也不存session而是把openid当用户ID存进user表后续所有接口用openid查用户。订单提交接口/api/order/create接收的body长这样{ openid: oABC...xyz, address_id: 123, items: [ { product_id: 456, quantity: 2 } ] }后端校验address_id归属该openid再查product库存事务控制在Service层用Connection.setAutoCommit(false)手动管理不是靠Spring的Transactional。3. 运行环境搭建Tomcat MySQL 微信开发者工具三件套3.1 Java后端部署Tomcat 7.0.96是黄金版本项目编译目标为Java 1.7所以别用Tomcat 10Servlet 4.0规范老老实实用Tomcat 7.0.96。下载后解压在conf/server.xml里确认端口Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 /把整个项目文件夹含WebContent/复制到webapps/下重命名为shopping。启动bin/startup.batWindows或startup.shMac/Linux访问http://localhost:8080/shopping/admin/login.jsp——这是管理后台入口账号密码在/doc/README.md里写着admin/123456。提示如果启动报java.lang.UnsupportedClassVersionError说明JDK版本太高。右键项目→Properties→Java Build Path→Libraries→Add Library→Server Runtime→选择Tomcat v7.0然后Project Facets里把Java Compiler设为1.7。3.2 MySQL初始化字符集必须是utf8mb4创建数据库时执行CREATE DATABASE shopping CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;然后导入/doc/database.sql。特别注意product.img_url字段类型是VARCHAR(255)但实际存的路径可能超长微信上传图片返回的临时链接很长所以建表后手动扩容ALTER TABLE product MODIFY img_url VARCHAR(500);连接URL在src/com/utils/DBUtil.java里private static final String URL jdbc:mysql://localhost:3306/shopping?useUnicodetruecharacterEncodingutf8mb4;漏掉?useUnicodetruecharacterEncodingutf8mb4会导致中文存成问号这是新手翻车第一高频点。3.3 小程序端配置填对域名才能调通API在微信开发者工具里打开小程序项目进project.config.json把appid换成你自己的测试号AppID。关键在utils/request.jsconst baseUrl http://localhost:8080/shopping; // 必须和Tomcat部署路径一致然后去微信公众平台后台mp.weixin.qq.com→开发管理→开发设置→服务器域名把localhost加到request合法域名里开发阶段允许填localhost上线必须换真实域名。注意微信开发者工具的“不校验合法域名”开关只对调试有效真机测试必须配域名否则wx.request直接fail。3.4 管理后台登录JSP页面背后的Session机制访问http://localhost:8080/shopping/admin/login.jsp输入admin/123456。登录成功后跳转到index.jsp顶部导航栏显示“欢迎管理员”。这个Session管理在AdminLoginServlet.java里实现HttpSession session request.getSession(); session.setAttribute(admin, admin); // 存入session response.sendRedirect(index.jsp);所有后台页面如product/list.jsp开头都有% if(session.getAttribute(admin) null) response.sendRedirect(login.jsp); %没用Filter做统一拦截而是每个JSP硬写校验——简单粗暴但符合教学项目定位。4. 关键业务链路实操从登录到发货一行行代码跑通4.1 小程序登录code换openid的完整链路小程序端pages/user/login.js里wx.login({ success: res { wx.request({ url: app.globalData.baseUrl /api/user/login, method: POST, data: { code: res.code }, success: res { if (res.data.code 200) { wx.setStorageSync(openid, res.data.data.openid); wx.switchTab({ url: /pages/index/index }); } } }) } })后端LoginServlet.java的doPost()String code request.getParameter(code); // 调用微信接口换openid String url https://api.weixin.qq.com/sns/jscode2session?appid APPID secret SECRET js_code code grant_typeauthorization_code; // 发送HTTP GET请求用HttpURLConnection // 解析返回JSON取openid字段 String openid json.get(openid).getAsString(); // 查库不存在则插入新用户 User user userDao.findByOpenid(openid); if (user null) { user new User(); user.setOpenid(openid); userDao.insert(user); } // 返回openid给小程序 response.getWriter().write({\code\:200,\msg\:\success\,\data\:{\openid\:\ openid \}});玄学点微信接口返回的session_key没存因为项目只用openid做用户标识session_key只在解密手机号时用——这正是下一节要讲的。4.2 获取手机号button open-typegetPhoneNumber的坑小程序pages/user/bind-phone.wxml里button open-typegetPhoneNumber bindgetphonenumbergetPhoneNumber绑定手机号/buttonbindgetphonenumber事件里getPhoneNumber(e) { if (e.detail.code) { wx.request({ url: app.globalData.baseUrl /api/user/bindPhone, method: POST, data: { openid: wx.getStorageSync(openid), encryptedData: e.detail.encryptedData, iv: e.detail.iv } }) } }后端BindPhoneServlet.java用AesUtils.decrypt()解密String sessionKey getSessionKey(openid); // 从数据库查上次登录存的session_key byte[] result AesUtils.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv)); String phoneJson new String(result, UTF-8); // 解析{phoneNumber:138****1234}避坑点getSessionKey(openid)必须查数据库项目在用户首次登录时就把session_key存进了user表的session_key字段否则解密必失败。很多教程教“每次登录都换session_key”但这里没这么做——因为session_key有效期2小时而用户绑定手机号动作通常在登录后立刻发生。4.3 加购与结算购物车数据存在哪小程序端购物车数据存在本地缓存// pages/cart/cart.js onLoad() { this.setData({ cartList: wx.getStorageSync(cart) || [] }); }, addToCart(product) { let cart wx.getStorageSync(cart) || []; const exist cart.find(item item.product_id product.id); if (exist) { exist.quantity 1; } else { cart.push({ product_id: product.id, quantity: 1 }); } wx.setStorageSync(cart, cart); }提交订单时才把cart数组传给后端wx.request({ url: /api/order/create, method: POST, data: { openid: wx.getStorageSync(openid), address_id: this.data.selectedAddress.id, items: this.data.cartList } })后端OrderServlet.java里校验库存for (CartItem item : items) { Product product productDao.findById(item.getProductId()); if (product.getStock() item.getQuantity()) { response.getWriter().write({\code\:400,\msg\:\商品 product.getName() 库存不足\}); return; } } // 扣库存UPDATE product SET stock stock - ? WHERE id ? // 插入order主表 // 插入order_item明细表 // 事务提交血泪经验扣库存必须用UPDATE ... SET stock stock - ?不能先SELECT再UPDATE否则并发下单会超卖。这个项目用单条SQL搞定没上Redis锁。4.4 后台发货状态变更与物流信息写入管理员在admin/order/list.jsp点击“发货”按钮触发a hrefOrderServlet?actionshiporderId% order.getId() %发货/aOrderServlet.java的doGet()处理String action request.getParameter(action); if (ship.equals(action)) { int orderId Integer.parseInt(request.getParameter(orderId)); Order order orderDao.findById(orderId); if (order.getStatus() 1) { // 只允许从“已支付”发到“已发货” order.setStatus(2); order.setShipTime(new Date()); orderDao.updateStatus(order); // 物流信息存到logistics表项目里没建此表实际用order表的logistics_no字段 response.sendRedirect(list.jsp?msg发货成功); } }小程序端订单列表页用setInterval每10秒轮询/api/order/detail?id123查status字段变化状态变2就更新UI显示“已发货”。提示轮询不是最优解但教学项目够用。真商用得上WebSocket或微信模板消息推送。5. 避坑指南95分项目里藏着的5个真实翻车点5.1 现象小程序调API返回404但Tomcat日志显示请求根本没进来原因微信开发者工具里utils/request.js的baseUrl写成了http://127.0.0.1:8080/shopping而Tomcat监听的是localhost某些系统hosts文件里127.0.0.1没映射到localhost导致DNS解析失败。解决统一用localhost或者在C:\Windows\System32\drivers\etc\hosts里加一行127.0.0.1 localhost。5.2 现象MySQL插入中文变问号但database.sql里明明写了CHARACTER SET utf8mb4原因DBUtil.java里的JDBC URL漏了?useUnicodetruecharacterEncodingutf8mb4或者MySQL服务端配置my.cnf里没设[mysqld] default-character-set utf8mb4。解决检查DBUtil.java的URL字符串登录MySQL执行SHOW VARIABLES LIKE character_set_%;确保character_set_database和character_set_server都是utf8mb4。5.3 现象管理员登录后台后点任何链接都跳回login.jsp原因web.xml里session-config没设cookie-http-onlyfalse/cookie-http-only而微信开发者工具的Cookie策略更严格导致JSESSIONID没传过去。解决在web.xml的session-config里加cookie-http-onlyfalse/cookie-http-only cookie-securefalse/cookie-secure5.4 现象商品图片在小程序里显示404但浏览器直接访问http://localhost:8080/shopping/upload/product/123.jpg能打开原因Tomcat默认不提供静态资源服务upload/目录不在WebContent/下而是在WebContent/同级的upload/文件夹里需要在web.xml里加Servlet映射servlet-mapping servlet-namedefault/servlet-name url-pattern/upload/*/url-pattern /servlet-mapping解决把upload/文件夹移到WebContent/内部或者按上述配置加映射。5.5 现象wx.chooseAddress()返回的地址在后台显示为空但小程序console.log里能看到数据原因小程序传参时用了JSON.stringify(address)后端request.getParameter(address)拿到的是字符串但代码里直接当对象用没反序列化。解决后端用com.alibaba.fastjson.JSON.parseObject(request.getParameter(address), Address.class)解析或者小程序端传address.province、address.city等单个字段。6. 进阶验证技巧用三步法确认业务逻辑真正跑通6.1 数据库层面验证用SELECT语句抓取关键状态快照不要只信前端UI直接查库确认状态流转。例如验证订单创建-- 查刚下的订单 SELECT id, user_id, status, total_price, create_time FROM order ORDER BY id DESC LIMIT 1; -- 查对应的订单明细 SELECT * FROM order_item WHERE order_id 123; -- 查商品库存是否扣减 SELECT stock FROM product WHERE id 456;如果order.status1已支付、order_item.quantity2、product.stock比下单前少2说明核心链路OK。我每次改完库存逻辑必跑这三条SQL比看日志快十倍。6.2 接口层面验证用curl绕过小程序直测后端当小程序调试卡壳用curl直打Java接口# 模拟小程序登录 curl -X POST http://localhost:8080/shopping/api/user/login \ -H Content-Type: application/x-www-form-urlencoded \ -d code013LQmjl27ZkFk0r9Vkl2zGtil2LQmjO # 模拟创建订单需先拿到openid curl -X POST http://localhost:8080/shopping/api/order/create \ -H Content-Type: application/json \ -d { openid: oABC...xyz, address_id: 1, items: [{product_id: 1, quantity: 1}] }好处排除小程序端JS错误干扰快速定位是后端逻辑问题还是前端传参问题。看到curl返回{code:200}就知道后端没问题。6.3 日志层面验证在关键节点加System.out.println项目没用Log4j但System.out.println够用。我在OrderServlet.java的createOrder()方法开头加System.out.println([DEBUG] 创建订单openid openid , address_id addressId);Tomcat控制台输出实时可见。比打断点快——尤其当你不确定请求到底进没进Servlet时第一行print就是定心丸。6.4 真机联调验证用手机扫二维码跑通全流程微信开发者工具的“预览”功能生成二维码用真机微信扫码。此时注意小程序端request.js的baseUrl必须改成局域网IP如http://192.168.1.100:8080/shoppingTomcat的server.xml里Connector标签加address0.0.0.0允许外网访问电脑防火墙放行8080端口手机和电脑连同一WiFi真机跑通意味着微信登录态、网络请求、图片加载、支付回调本项目没接入支付但预留了/api/order/pay接口全部可用。从那以后我每次交付项目必用真机扫三次码——第一次测登录第二次测下单第三次测后台发货缺一不可。希望帮到你。本文还有配套的精品资源点击获取