一、数据表设计

create table `foodie-shop-dev`.user_address ( id varchar(64) not null comment '地址主键id' primary key, user_id varchar(64) not null comment '关联用户id', receiver varchar(32) not null comment '收件人姓名', mobile varchar(32) not null comment '收件人手机号', province varchar(32) not null comment '省份', city varchar(32) not null comment '城市', district varchar(32) not null comment '区县', detail varchar(128) not null comment '详细地址', extand varchar(128) null comment '扩展字段', is_default int null comment '是否默认地址', created_time datetime not null comment '创建时间', updated_time datetime not null comment '更新时间' ) comment '用户地址表 ' charset = utf8mb4;
二、功能说明
/** * 用户在确认订单页面,可以针对收货地址做如下操作: * 1. 查询用户的所有收货地址列表 * 2. 新增收货地址 * 3. 删除收货地址 * 4. 修改收货地址 * 5. 设置默认地址 */
三、service 子模块实现
1、接口定义

package com.imooc.service; import com.imooc.pojo.UserAddress; import com.imooc.pojo.bo.AddressBO; import java.util.List; public interface AddressService { /** *查询用户的所有收货地址列表 * @return */ public List<UserAddress> queryAll(String userId); /**新增收货地址 * * @param * @return */ public void addNewUserAddress (AddressBO userAddressBO); /**删除收货地址 * * @param userId * @return */ public void deleteUserAddress(String userId, String addressId); /**修改收货地址 * * @param userAddressBO * @return */ public void updateUserAddress(AddressBO userAddressBO); /** * 设置默认地址 * @param userId * @return */ public void updateUserAddressToBeDefault(String userId, String addressId); }
2、BO定义(前端发送的数据)

package com.imooc.pojo.bo; /** * 用户新增或修改地址的BO */ public class AddressBO { private String addressId; private String userId; private String receiver; private String mobile; private String province; private String city; private String district; private String detail; public String getAddressId() { return addressId; } public void setAddressId(String addressId) { this.addressId = addressId; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getDistrict() { return district; } public void setDistrict(String district) { this.district = district; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } }
3、接口实现

package com.imooc.service.impl; import com.imooc.enums.YesOrNo; import com.imooc.mapper.UserAddressMapper; import com.imooc.pojo.UserAddress; import com.imooc.pojo.bo.AddressBO; import com.imooc.service.AddressService; import org.n3r.idworker.Sid; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; @Service public class AddressServiceImpl implements AddressService { @Autowired private UserAddressMapper userAddressMapper; @Autowired private Sid sid; @Transactional(propagation = Propagation.SUPPORTS) @Override public List<UserAddress> queryAll(String userId) { UserAddress ua = new UserAddress(); ua.setUserId(userId); return userAddressMapper.select(ua); } @Transactional(propagation = Propagation.SUPPORTS) @Override public void addNewUserAddress(AddressBO addressBO) { // 1. 判断当前用户是否存在地址,如果没有,则新增为‘默认地址’ Integer isDefault = 0; List<UserAddress> addressList = this.queryAll(addressBO.getUserId()); if (addressList == null || addressList.isEmpty() || addressList.size() == 0) { isDefault = 1; } String addressId = sid.nextShort(); // 2. 保存地址到数据库 UserAddress newAddress = new UserAddress(); BeanUtils.copyProperties(addressBO, newAddress); newAddress.setId(addressId); newAddress.setIsDefault(isDefault); newAddress.setCreatedTime(new Date()); newAddress.setUpdatedTime(new Date()); userAddressMapper.insert(newAddress); } @Transactional(propagation = Propagation.REQUIRED) @Override public void deleteUserAddress(String userId, String addressId) { UserAddress userAddress=new UserAddress(); userAddress.setId(addressId); userAddress.setUserId(userId); userAddressMapper.delete(userAddress); } @Transactional(propagation = Propagation.REQUIRED) @Override public void updateUserAddress(AddressBO addressBO) { String addressId = addressBO.getAddressId(); UserAddress pendingAddress = new UserAddress(); BeanUtils.copyProperties(addressBO, pendingAddress); pendingAddress.setId(addressId); pendingAddress.setUpdatedTime(new Date()); userAddressMapper.updateByPrimaryKeySelective(pendingAddress); } @Transactional(propagation = Propagation.REQUIRED) @Override public void updateUserAddressToBeDefault(String userId, String addressId) { // 1. 查找默认地址,设置为不默认 UserAddress queryAddress = new UserAddress(); queryAddress.setUserId(userId); queryAddress.setIsDefault(YesOrNo.YES.type); List<UserAddress> list = userAddressMapper.select(queryAddress); for (UserAddress ua : list) { ua.setIsDefault(YesOrNo.NO.type); userAddressMapper.updateByPrimaryKeySelective(ua); } // 2. 根据地址id修改为默认的地址 UserAddress defaultAddress = new UserAddress(); defaultAddress.setId(addressId); defaultAddress.setUserId(userId); defaultAddress.setIsDefault(YesOrNo.YES.type); userAddressMapper.updateByPrimaryKeySelective(defaultAddress); } }
四、api子模块实现
1、手机号码判断工具类

package com.imooc.utils; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MobileEmailUtils { public static boolean checkMobileIsOk(String mobile) { String regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(17[013678])|(18[0,5-9]))\\d{8}$"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(mobile); boolean isMatch = m.matches(); return isMatch; } public static boolean checkEmailIsOk(String email) { boolean isMatch = true; if (!email.matches("[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+")) { isMatch = false; } return isMatch; } }
2、Controller实现

package com.imooc.controller; import com.imooc.pojo.UserAddress; import com.imooc.pojo.bo.AddressBO; import com.imooc.service.AddressService; import com.imooc.utils.IMOOCJSONResult; import com.imooc.utils.MobileEmailUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @Api(value = "收货地址相关", tags = {"收货地址相关的api接口"}) @RequestMapping("address") @RestController public class AddressController { /** * 用户在确认订单页面,可以针对收货地址做如下操作: * 1. 查询用户的所有收货地址列表 * 2. 新增收货地址 * 3. 删除收货地址 * 4. 修改收货地址 * 5. 设置默认地址 */ @Autowired private AddressService addressService; @ApiOperation(value = "根据用户id查询收货地址列表", notes = "根据用户id查询收货地址列表", httpMethod = "POST") @PostMapping("/list") public IMOOCJSONResult list( @RequestParam String userId) { if (StringUtils.isBlank(userId)) { return IMOOCJSONResult.errorMsg(""); } List<UserAddress> list = addressService.queryAll(userId); return IMOOCJSONResult.ok(list); } @ApiOperation(value = "用户新增地址", notes = "用户新增地址", httpMethod = "POST") @PostMapping("/add") public IMOOCJSONResult add(@RequestBody AddressBO addressBO) { IMOOCJSONResult checkRes = checkAddress(addressBO); if (checkRes.getStatus() != 200) { return checkRes; } addressService.addNewUserAddress(addressBO); return IMOOCJSONResult.ok(); } private IMOOCJSONResult checkAddress(AddressBO addressBO) { String receiver = addressBO.getReceiver(); if (StringUtils.isBlank(receiver)) { return IMOOCJSONResult.errorMsg("收货人不能为空"); } if (receiver.length() > 12) { return IMOOCJSONResult.errorMsg("收货人姓名不能太长"); } String mobile = addressBO.getMobile(); if (StringUtils.isBlank(mobile)) { return IMOOCJSONResult.errorMsg("收货人手机号不能为空"); } if (mobile.length() != 11) { return IMOOCJSONResult.errorMsg("收货人手机号长度不正确"); } boolean isMobileOk = MobileEmailUtils.checkMobileIsOk(mobile); if (!isMobileOk) { return IMOOCJSONResult.errorMsg("收货人手机号格式不正确"); } String province = addressBO.getProvince(); String city = addressBO.getCity(); String district = addressBO.getDistrict(); String detail = addressBO.getDetail(); if (StringUtils.isBlank(province) || StringUtils.isBlank(city) || StringUtils.isBlank(district) || StringUtils.isBlank(detail)) { return IMOOCJSONResult.errorMsg("收货地址信息不能为空"); } return IMOOCJSONResult.ok(); } @ApiOperation(value = "用户修改地址", notes = "用户修改地址", httpMethod = "POST") @PostMapping("/update") public IMOOCJSONResult update(@RequestBody AddressBO addressBO) { if (StringUtils.isBlank(addressBO.getAddressId())) { return IMOOCJSONResult.errorMsg("修改地址错误:addressId不能为空"); } IMOOCJSONResult checkRes = checkAddress(addressBO); if (checkRes.getStatus() != 200) { return checkRes; } addressService.updateUserAddress(addressBO); return IMOOCJSONResult.ok(); } @ApiOperation(value = "用户删除地址", notes = "用户删除地址", httpMethod = "POST") @PostMapping("/delete") public IMOOCJSONResult delete( @RequestParam String userId, @RequestParam String addressId) { if (StringUtils.isBlank(userId) || StringUtils.isBlank(addressId)) { return IMOOCJSONResult.errorMsg(""); } addressService.deleteUserAddress(userId, addressId); return IMOOCJSONResult.ok(); } @ApiOperation(value = "用户设置默认地址", notes = "用户设置默认地址", httpMethod = "POST") @PostMapping("/setDefalut") public IMOOCJSONResult setDefalut( @RequestParam String userId, @RequestParam String addressId) { if (StringUtils.isBlank(userId) || StringUtils.isBlank(addressId)) { return IMOOCJSONResult.errorMsg(""); } addressService.updateUserAddressToBeDefault(userId, addressId); return IMOOCJSONResult.ok(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理