news 2026/5/30 20:01:53

Reggie1项目四:用户端功能模块(地址管理 + 购物车)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Reggie1项目四:用户端功能模块(地址管理 + 购物车)

今日核心:完成用户端地址管理和购物车功能。这两个模块涵盖了用户端开发中最常用的 Session 管理、ThreadLocal 上下文传递、数据库字段约束处理、MyBatis-Plus 自动填充等核心技能。

一、今日完成的功能模块

模块功能接口数量状态
地址管理新增、查询列表、查询默认、设置默认、修改、删除7个✅ 完成
购物车添加、查询列表、清空3个✅ 完成

二、核心技术点

2.1 Session 管理用户端登录状态

问题:用户端登录后,后续请求如何识别用户身份?

解决方案:登录成功后,将用户 ID 存入 Session:

session.setAttribute("user", dbUser.getId());

后续请求中,从 Session 获取用户 ID:

Long userId = (Long) session.getAttribute("user"); if (userId == null) { return R.error("用户未登录"); }

2.2 过滤器中的用户端登录判断

LoginCheckFilter中,需要同时处理管理端和用户端的登录状态:

// 管理端判断 if (request.getSession().getAttribute("employee") != null) { Long empId = (Long) request.getSession().getAttribute("employee"); BaseContext.setCurrentId(empId); filterChain.doFilter(request, response); return; } // 用户端判断 if (request.getSession().getAttribute("user") != null) { Long userId = (Long) request.getSession().getAttribute("user"); BaseContext.setCurrentId(userId); filterChain.doFilter(request, response); return; }

2.3 白名单设计

需要放行的路径(不需要登录即可访问):

String[] urls = new String[]{ "/employee/login", "/employee/logout", "/backend/**", "/front/**", "/user/sendMsg", "/user/login", "/user/logout", "/common/**", "/dish/user/list", "/setmeal/user/list" // 注意:/addressBook/** 不在白名单中,需要登录后访问 };

2.4 公共字段自动填充

AddressBook实体类中的createUserupdateUsercreateTimeupdateTime使用 MyBatis-Plus 自动填充:

@TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; @TableField(fill = FieldFill.INSERT) private Long createUser; @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser;

2.5 数据库字段约束处理

遇到的坑address_book表中的sex字段设置为NOT NULL且无默认值,但前端不传该字段,导致插入失败。

解决方案:修改数据库表结构,允许sex为 NULL:

ALTER TABLE address_book MODIFY COLUMN sex INT NULL;

三、地址管理模块详解

3.1 接口清单

接口方法路径说明
新增地址POST/addressBook添加收货地址
查询列表GET/addressBook/list获取当前用户所有地址
查询默认GET/addressBook/default获取默认地址
设置默认PUT/addressBook/default设置指定地址为默认
修改地址PUT/addressBook编辑地址信息
删除地址DELETE/addressBook删除地址
根据ID查询GET/addressBook/{id}获取单个地址详情

3.2 核心代码:新增地址

@PostMapping public R<AddressBook> save(@RequestBody AddressBook addressBook) { // 从 Session 获取当前登录用户 ID Long userId = (Long) session.getAttribute("user"); if (userId == null) { return R.error("用户未登录"); } addressBook.setUserId(userId); addressBookService.save(addressBook); return R.success(addressBook); }

3.3 核心代码:设置默认地址

@PutMapping("/default") public R<AddressBook> setDefault(@RequestBody AddressBook addressBook) { Long userId = (Long) session.getAttribute("user"); if (userId == null) { return R.error("用户未登录"); } // 1. 将当前用户的所有地址设为非默认 LambdaQueryWrapper<AddressBook> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(AddressBook::getUserId, userId); AddressBook update = new AddressBook(); update.setIsDefault(0); addressBookService.update(update, wrapper); // 2. 将指定地址设为默认 addressBook.setIsDefault(1); addressBookService.updateById(addressBook); return R.success(addressBook); }

四、购物车模块详解

4.1 接口清单

接口方法路径说明
添加POST/shoppingCart/add添加菜品/套餐到购物车(数量+1)
查询列表GET/shoppingCart/list获取当前用户购物车内容
清空DELETE/shoppingCart/clean清空购物车

4.2 核心代码:添加购物车

@PostMapping("/add") public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart) { Long userId = (Long) session.getAttribute("user"); if (userId == null) { return R.error("用户未登录"); } shoppingCart.setUserId(userId); // 查询当前菜品/套餐是否已在购物车中 LambdaQueryWrapper<ShoppingCart> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ShoppingCart::getUserId, userId); if (shoppingCart.getDishId() != null) { wrapper.eq(ShoppingCart::getDishId, shoppingCart.getDishId()); wrapper.eq(ShoppingCart::getDishFlavor, shoppingCart.getDishFlavor()); } else { wrapper.eq(ShoppingCart::getSetmealId, shoppingCart.getSetmealId()); } ShoppingCart cart = shoppingCartService.getOne(wrapper); if (cart != null) { // 已存在,数量+1 cart.setNumber(cart.getNumber() + 1); shoppingCartService.updateById(cart); } else { // 不存在,新增,数量设为1 shoppingCart.setNumber(1); shoppingCart.setCreateTime(LocalDateTime.now()); shoppingCartService.save(shoppingCart); cart = shoppingCart; } return R.success(cart); }

五、遇到的坑及解决方案

坑一:新增地址返回“系统繁忙”

错误信息

Column 'create_user' cannot be null

原因/addressBook/**被错误地加到了白名单中,导致请求不经过过滤器,BaseContext中没有用户 ID,自动填充失败。

解决方案:从白名单中删除/addressBook/**,让请求经过过滤器。

坑二:sex字段没有默认值

错误信息

Field 'sex' doesn't have a default value

原因:数据库表中sex字段设置为NOT NULL且无默认值,但前端不传该字段。

解决方案:修改数据库表结构,允许sex为 NULL:

ALTER TABLE address_book MODIFY COLUMN sex INT NULL;

坑三:APIFox 离线空间无法管理 Cookie

问题:在 APIFox 离线空间中测试时,登录后的 Session 无法自动携带。

解决方案:改用浏览器 Console 测试,浏览器会自动管理 Cookie。

六、测试方法(浏览器 Console)

6.1 登录

fetch('/user/login', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({phone: '13812345678', code: '验证码'}) }) .then(res => res.json()) .then(data => console.log('登录结果:', data));

6.2 新增地址

fetch('/addressBook', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ consignee: '张三', phone: '13812345678', detail: '北京市朝阳区xxx', label: '家' }) }) .then(res => res.json()) .then(data => console.log('新增地址结果:', data));

6.3 查询地址列表

fetch('/addressBook/list') .then(res => res.json()) .then(data => console.log('地址列表:', data));

6.4 添加购物车

fetch('/shoppingCart/add', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ dishId: '1397849739276890114', name: '辣子鸡', amount: 7800 }) }) .then(res => res.json()) .then(data => console.log('添加购物车结果:', data));

6.5 查询购物车

fetch('/addressBook', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ consignee: '张三', phone: '13812345678', detail: '北京市朝阳区xxx', label: '家' }) }) .then(res => res.json()) .then(data => console.log('新增地址结果:', data));

七、面试高频问题及回答

Q1:用户端如何判断登录状态?

:用户登录成功后,将用户 ID 存入 Session。后续请求通过过滤器判断 Session 中是否存在user属性,如果存在则放行,否则返回NOTLOGIN

Q2:为什么地址管理不能放在白名单里?

:地址管理需要获取当前登录用户的 ID 来关联地址。如果放在白名单里,请求不经过过滤器,BaseContext中没有用户 ID,MyBatis-Plus 自动填充createUser等字段时会填入null,导致数据库报错。

Q3:购物车中同一菜品多次添加如何处理?

:先查询该菜品是否已在当前用户的购物车中。如果存在,则数量 +1;如果不存在,则新增一条记录,数量设为 1。

Q4:APIFox 测试时为什么浏览器正常但 APIFox 不正常?

:浏览器会自动管理 Cookie,登录成功后后续请求会自动携带 Session ID。APIFox 离线空间不支持自动管理 Cookie,需要手动设置或切换到在线项目。

八、项目当前进度

模块状态
管理端(员工、分类、菜品、套餐、订单)✅ 全部完成
用户端登录✅ 完成
用户端菜品/套餐展示✅ 完成
用户端地址管理✅ 完成
用户端购物车✅ 完成

九、写在最后给观众老爷们

为什么会有六那样的测试方法呢?

因为用户端的前端映射出现了问题?我也不知道具体是什么问题,请看图:

本来应该长这样才对:

为什么会出现这种情况这种问题?看到的大哥给支支招呗!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/29 13:59:02

大语言模型与进化算法结合的Verilog自动生成技术

1. 项目概述&#xff1a;当大语言模型遇上进化算法在数字电路设计领域&#xff0c;Verilog作为主流的硬件描述语言(HDL)&#xff0c;其编写质量直接影响芯片性能和开发效率。传统手工编写方式面临三大痛点&#xff1a;开发周期长&#xff08;平均每个模块需2-3天&#xff09;、…

作者头像 李华
网站建设 2026/5/30 14:21:58

如何免费获得工业级热物理计算能力?CoolProp终极指南

如何免费获得工业级热物理计算能力&#xff1f;CoolProp终极指南 【免费下载链接】CoolProp Thermophysical properties for the masses 项目地址: https://gitcode.com/gh_mirrors/co/CoolProp 还在为昂贵的商业热物理软件发愁吗&#xff1f;作为一名工程师或科研人员&…

作者头像 李华
网站建设 2026/5/30 19:28:32

Raspberry Pi Pico W开发利器:Rshell与REPL交互式编程实战指南

1. 项目概述与核心价值 如果你手头有一块 Raspberry Pi Pico W&#xff0c;正兴致勃勃地想用它做点物联网小玩意儿&#xff0c;比如远程控制个LED、读取个传感器数据&#xff0c;或者搭建一个简单的Web服务器&#xff0c;那你肯定绕不开一个环节&#xff1a;怎么把写好的代码弄…

作者头像 李华
网站建设 2026/5/30 16:43:09

别再傻傻分不清!Linux下.rpm、.src.rpm、noarch.rpm到底该怎么选?

Linux下.rpm、.src.rpm、noarch.rpm的终极选择指南第一次在Linux服务器上安装软件时&#xff0c;面对各种以.rpm、.src.rpm、noarch.rpm结尾的包文件&#xff0c;我完全懵了。记得当时为了部署一个简单的Web服务&#xff0c;我下载了错误的包类型&#xff0c;结果不仅安装失败&…

作者头像 李华
网站建设 2026/5/29 13:51:09

选NRZ还是RZ?从5G前传和高速光模块设计,看信号格式的实战权衡

NRZ与RZ信号在5G前传与高速光模块中的工程化抉择清晨六点&#xff0c;某光模块厂商的实验室依然灯火通明。工程师李明正在调试一款400G光模块&#xff0c;示波器上跳动的波形让他眉头紧锁——在传输距离增加到10公里后&#xff0c;NRZ信号的误码率突然飙升。这个场景在高速互连…

作者头像 李华