导入地址簿功能代码

分析

产品原型:

 

可以存储多个地址,但只能有一个默认地址。修改地址这个功能不能只是修改,还需要先进行数据回显。

接口设计:

新增:

查询所有地址:

查询默认地址:

修改:

删除:

根据id查询地址:

设置默认地址(本质是修改):

代码

查询所有地址

controller层:

1.根据接口文档,请求参数其实就是用户id,先获取用户id。通过创建一个对象来获取,其中对象除了获得的userid没有其他属性值了。

AddressBook addressBook=new AddressBook();
Long currentId = BaseContext.getCurrentId();
addressBook.setUserId(currentId);

通过userid进行查询:

List<AddressBook>list =addRessBookService.list(addressBook);

完整代码,泛型是AddressBook的list集合原因就在于返回的地址可能不止只有一个,并且返回类型要写。

serviceimpl:主要注意这是有返回结果的,需要定义,不定义就直接return+mapper.list

 @Override
    public List<AddressBook> list(AddressBook addressBook) {
        List<AddressBook> list= addRessBookMapper.list(addressBook);
return list;
    }

mapper使用动态查询

<select id="list" parameterType="AddressBook" resultType="AddressBook">
    select * from address_book
    <where>
        <if test="userId != null"> and user_id = #{userId} </if>
        <if test="phone != null"> and phone = #{phone} </if>
        <if test="isDefault != null"> and is_default = #{isDefault} </if>
    </where>
</select>

新增地址

controller:

/**
 * 添加地址
 */
@PostMapping
@ApiOperation("新增地址")
public Result add(@RequestBody  AddressBook addressBook){
    addressBookService.save(addressBook);
    return Result.success();
}

实现层:

一定要获取用户id,这是保证加到哪个用户的购物车地址

并且不能设置为默认地址。

addressBook.setUserId(BaseContext.getCurrentId())
用户身份绑定:从 BaseContext 上下文中获取当前登录用户的ID,并将其设置到 addressBook 对象中
数据归属:确保每条地址记录都能关联到正确的用户,实现用户数据隔离
addressBook.setIsDefault(0)
默认状态初始化:将新增地址设置为非默认地址(0表示非默认)
业务规则:新添加的地址默认不作为用户的默认收货地址,符合常规业务逻辑

   /**
     * 添加地址
     */
    @Override
    public void save(AddressBook addressBook) {
       addressBook.setUserId (BaseContext.getCurrentId());
       addressBook.setIsDefault(0);//设置成为非默认
addressBookMapper.save(addressBook);
    }

mapper:

@Insert("insert into address_book" +
        "        (user_id, consignee, phone, sex, province_code, province_name, city_code, city_name, district_code," +
        "         district_name, detail, label, is_default)" +
        "        values (#{userId}, #{consignee}, #{phone}, #{sex}, #{provinceCode}, #{provinceName}, #{cityCode}, #{cityName}," +
        "                #{districtCode}, #{districtName}, #{detail}, #{label}, #{isDefault})")
void save(AddressBook addressBook);

根据id进行查询

controller:

@GetMapping("/{id}")
    @ApiOperation("根据id进行查询")
    public Result<AddressBook> getById(@PathVariable Long id){
    AddressBook addressBook = addressBookService.getById(id);
return Result.success(addressBook);
}

serviceimpl

/**
 * 根据id查询
 * @param id
 * @return
 */
@Override
public AddressBook getById(Long id) {
   AddressBook addressBook= addressBookMapper.getById(id);
return addressBook;
}

mapper

/**
 * 根据id查询
 * @param id
 * @return
 */
@Select("select * from address_book where id = #{id}")
AddressBook getById(Long id);

根据id进行修改

controller

/**
 * 根据id修改地址
 */
@PutMapping
@ApiOperation("修改地址")
    public Result update(@RequestBody AddressBook addressBook){
    addressBookService.update(addressBook);
    return Result.success();
}

serviceimpl

/**
 * 根据id进行修改
 * @param addressBook
 */
@Override
public void update(AddressBook addressBook) {
    addressBookMapper.update(addressBook);
}

mapper

<update id="update" parameterType="addressBook">
    update address_book
    <set>
        <if test="consignee != null"> consignee = #{consignee}, </if>
        <if test="sex != null"> sex = #{sex}, </if>
        <if test="phone != null"> phone = #{phone}, </if>
        <if test="detail != null"> detail = #{detail}, </if>
        <if test="label != null"> label = #{label}, </if>
        <if test="isDefault != null"> is_default = #{isDefault}, </if>
    </set>
    where id = #{id}
</update>

设置默认地址

@PutMapping("/default")
@ApiOperation("设置默认地址")
public  Result setDefault(@RequestBody AddressBook addressBook){
    addressBookService.setDefault(addressBook);
    return Result.success();
}
   @Transactional
    @Override
    public void setDefault(AddressBook addressBook) {
//1、将当前用户的所有地址修改为非默认地址 update address_book set is_default = ? where user_id = ?
        addressBook.setIsDefault(0);
        addressBook.setUserId(BaseContext.getCurrentId());
        addressBookMapper.updateIsDefaultByUserId(addressBook);

        //2、将当前地址改为默认地址 update address_book set is_default = ? where id = ?
        addressBook.setIsDefault(1);
        addressBookMapper.update(addressBook);
    }
@Update("update address_book set is_default = #{isDefault} where user_id = #{userId}")
void updateIsDefaultByUserId(AddressBook addressBook);

根据id删除

/**
 * 根据id删除
 */
@DeleteMapping
@ApiOperation("根据id删除地址")
public Result deleteById(Long id) {
    addressBookService.deleteById(id);
    return Result.success();
}
/**
 * 根据id删除地址
 *
 * @param id
 */
public void deleteById(Long id) {
    addressBookMapper.deleteById(id);
}
/**
 * 根据id删除地址
 * @param id
 */
@Delete("delete from address_book where id = #{id}")
void deleteById(Long id);

用户下单

分析

买的哪些商品和数量可以通过购物车模块中的查询购物车获得。

订单总金额需要通过程序获取,有两部分:菜品费用+其他费用(餐盒费配送费等等)。

其他三个疑问都可以在地址簿中解决。

用户点餐业务流程:

接口分析:

接口文档:

数据库设计:

代码

1.controller层

根据接口文档的返回数据可得,需要使用一个vo类进行封装:

public class OrderController {
    @Autowired
    private OrderService orderService;

    @PostMapping("/submit")
    @ApiOperation("用户下单")
    public Result<OrderSubmitVO> submit(@RequestBody OrdersSubmitDTO ordersSubmitDTO){
OrderSubmitVO orderSubmitVO=orderService.submitOrder(ordersSubmitDTO);
return Result.success(orderSubmitVO);

    }

2.serviceimpl层

要实现用户下单的话需要实现:

1.向订单表插入一条数据

2.向订单明细表插入n条数据

3.清空购物车(下单成功后)

4.返回vo数据给前端

在实现这四步之前,有两个问题不能忽略,即用户收货地址有没有问题,用户有下单请求,但购物车为空又该怎么办。即需要处理业务异常:

//0.考虑并处理业务异常:
//异常1:地址簿为空不能下单
AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
if (addressBook==null){
    throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
}
//异常2:购物车为空不能下单
Long userId = BaseContext.getCurrentId();
//list方法需要传入一个shoppingcart对象
ShoppingCart shoppingCart=new ShoppingCart();
shoppingCart.setUserId(userId);
List<ShoppingCart> shoppingCartList = shoppingCartMapper.list(shoppingCart);
if (shoppingCartList ==null ||shoppingCartList.size()==0){
    throw  new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
}

1.向订单表插入一条数据:

order类:

有很多字段,在插入数据之前得封装数据,而有部分数据封装在dto,只需要进行数据拷贝:

Orders orders = new Orders();
//属性拷贝
BeanUtils.copyProperties(ordersSubmitDTO,orders); 

但数据不全,仍有部分数据需要自己进行设置:

 //自己设置剩下的参数
 orders.setOrderTime(LocalDateTime.now());//下单时间
 orders.setPayStatus(orders.UN_PAID);//支付状态:未支付
 orders.setStatus(orders.PENDING_PAYMENT);//订单状态
 orders.setNumber(String.valueOf(System.currentTimeMillis()));//订单号可以使用当前系统时间的时间戳,需要强转
 orders.setPhone(addressBook.getPhone());//获取手机号,因为业务异常创建了地址类。
 orders.setConsignee(addressBook.getConsignee());
 orders.setUserId(userId);
orderMapper.insert(orders);

mapper.xml(需要返回主键值):

<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    insert into orders(user_id,number,status,address_book_id,order_time,checkout_time,pay_method,pay_status,amount,remark,user_name,phone,address,consignee,estimated_delivery_time,delivery_status,pack_amount,tableware_number,tableware_status)
    values(#{userId},#{number},#{status},#{addressBookId},#{orderTime},#{checkoutTime},#{payMethod},#{payStatus},#{amount},#{remark},#{userName},#{phone},#{address},#{consignee},#{estimatedDeliveryTime},#{deliveryStatus},#{packAmount},#{tablewareNumber},#{tablewareStatus})

</insert>

2.向订单明细表插入n条数据:

//2.向订单明细表插入n条数据,订单明细就看购物车数据
List<OrderDetail> orderDetailList = new ArrayList<>();
for (ShoppingCart cart : shoppingCartList) {
    OrderDetail orderDetail = new OrderDetail();///订单明细
    BeanUtils.copyProperties(cart,orderDetail);
//设置该订单详情所属的订单 ID。这里使用的是刚刚插入订单表时生成的主键 ID(即 orders.getId()),建立订单和订单详情之间的关联关系。
    orderDetail.setOrderId(orders.getId());//上面获取id就用在这里,设置当前订单明细关联的订单id
    orderDetailList.add(orderDetail);
    //在for循环里面写mapper方法就是单条插入
}
//在for循环外面写就是批量插入,也就有了定义List集合List<OrderDetail> orderDetailList = new ArrayList<>();
orderDetailMapper.insertBatch(orderDetailList);

xml:

<insert id="insertBatch">
    insert into order_detail(name,image,order_id, dish_id, setmeal_id, dish_flavor, number, amount) values
    <foreach collection="orderDetaillist" item="od" separator=",">
    (#{od.name},#{od.image},#{od.orderId},#{od.dishId},#{od.setmealId},#{od.dishFlavor},#{od.number},#{od.amount})
    </foreach>
</insert>

3.清空购物车(下单成功后):

shoppingCartMapper.deleteByUserId(userId);

4.返回vo数据给前端:

OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
        .id(orders.getId())
        .orderNumber(orders.getNumber())
        .orderAmount(orders.getAmount())
        .build();
return orderSubmitVO;

订单支付

微信支付介绍

流程:

准备工作:

1.调用预支付接口,如何保证数据安全?

即对数据加密解密:

获得微信平台证书和商户私钥

2.微信后台如何调用到商户系统?

代码导入

进行支付相关配置:

填写格式如图:

代码讲解

流程图:

从申请微信支付开始,请求发送到ordercontroller中:

OrderPaymentDTO:

WeChatUtil这个工具类很重要,第五步调用是微信下单接口就与这个工具类有关。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐