苍穹外卖day8
用户下单
导入地址簿
需求分析
需要实现的功能如图一
- 新增地址:
- 与新增员工相似,将用户id,信息等插入数据库
- 查询所有信息
- 根据用户id查询用户所有地址信息
- 查询默认地址
- 查询当前用户default为1的地址
- 根据id修改地址
- 接收前端传入地址更新数据库中的内容
- 根据id删除地址
- 根据主键id删除数据库的地址
- 根据id查询地址
- 根据主键id查询地址
- 设置默认地址
- 根据主键id更新default
Controller
packagecom.sky.controller.user;importcom.sky.context.BaseContext;importcom.sky.entity.AddressBook;importcom.sky.result.Result;importcom.sky.service.AddressBookService;importio.swagger.annotations.Api;importio.swagger.annotations.ApiOperation;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importjava.util.List;@RestController@RequestMapping("/user/addressBook")@Api(tags="C端地址簿接口")publicclassAddressBookController{@AutowiredprivateAddressBookServiceaddressBookService;/** * 查询当前登录用户的所有地址信息 * * @return */@GetMapping("/list")@ApiOperation("查询当前登录用户的所有地址信息")publicResult<List<AddressBook>>list(){AddressBookaddressBook=newAddressBook();addressBook.setUserId(BaseContext.getCurrentId());List<AddressBook>list=addressBookService.list(addressBook);returnResult.success(list);}/** * 新增地址 * * @param addressBook * @return */@PostMapping@ApiOperation("新增地址")publicResultsave(@RequestBodyAddressBookaddressBook){addressBookService.save(addressBook);returnResult.success();}@GetMapping("/{id}")@ApiOperation("根据id查询地址")publicResult<AddressBook>getById(@PathVariableLongid){AddressBookaddressBook=addressBookService.getById(id);returnResult.success(addressBook);}/** * 根据id修改地址 * * @param addressBook * @return */@PutMapping@ApiOperation("根据id修改地址")publicResultupdate(@RequestBodyAddressBookaddressBook){addressBookService.update(addressBook);returnResult.success();}/** * 设置默认地址 * * @param addressBook * @return */@PutMapping("/default")@ApiOperation("设置默认地址")publicResultsetDefault(@RequestBodyAddressBookaddressBook){addressBookService.setDefault(addressBook);returnResult.success();}/** * 根据id删除地址 * * @param id * @return */@DeleteMapping@ApiOperation("根据id删除地址")publicResultdeleteById(Longid){addressBookService.deleteById(id);returnResult.success();}/** * 查询默认地址 */@GetMapping("default")@ApiOperation("查询默认地址")publicResult<AddressBook>getDefault(){//SQL:select * from address_book where user_id = ? and is_default = 1AddressBookaddressBook=newAddressBook();addressBook.setIsDefault(1);addressBook.setUserId(BaseContext.getCurrentId());List<AddressBook>list=addressBookService.list(addressBook);if(list!=null&&list.size()==1){returnResult.success(list.get(0));}returnResult.error("没有查询到默认地址");}}Service实现类
packagecom.sky.service.impl;importcom.sky.context.BaseContext;importcom.sky.entity.AddressBook;importcom.sky.mapper.AddressBookMapper;importcom.sky.service.AddressBookService;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.util.List;@Service@Slf4jpublicclassAddressBookServiceImplimplementsAddressBookService{@AutowiredprivateAddressBookMapperaddressBookMapper;/** * 条件查询 * * @param addressBook * @return */publicList<AddressBook>list(AddressBookaddressBook){returnaddressBookMapper.list(addressBook);}/** * 新增地址 * * @param addressBook */publicvoidsave(AddressBookaddressBook){addressBook.setUserId(BaseContext.getCurrentId());addressBook.setIsDefault(0);addressBookMapper.insert(addressBook);}/** * 根据id查询 * * @param id * @return */publicAddressBookgetById(Longid){AddressBookaddressBook=addressBookMapper.getById(id);returnaddressBook;}/** * 根据id修改地址 * * @param addressBook */publicvoidupdate(AddressBookaddressBook){addressBookMapper.update(addressBook);}/** * 设置默认地址 * * @param addressBook */@TransactionalpublicvoidsetDefault(AddressBookaddressBook){//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);}/** * 根据id删除地址 * * @param id */publicvoiddeleteById(Longid){addressBookMapper.deleteById(id);}}Mapper
packagecom.sky.mapper;importcom.sky.entity.AddressBook;importorg.apache.ibatis.annotations.*;importjava.util.List;@MapperpublicinterfaceAddressBookMapper{/** * 条件查询 * @param addressBook * @return */List<AddressBook>list(AddressBookaddressBook);/** * 新增 * @param addressBook */@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})")voidinsert(AddressBookaddressBook);/** * 根据id查询 * @param id * @return */@Select("select * from address_book where id = #{id}")AddressBookgetById(Longid);/** * 根据id修改 * @param addressBook */voidupdate(AddressBookaddressBook);/** * 根据 用户id修改 是否默认地址 * @param addressBook */@Update("update address_book set is_default = #{isDefault} where user_id = #{userId}")voidupdateIsDefaultByUserId(AddressBookaddressBook);/** * 根据id删除地址 * @param id */@Delete("delete from address_book where id = #{id}")voiddeleteById(Longid);}<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.sky.mapper.AddressBookMapper"><selectid="list"parameterType="AddressBook"resultType="AddressBook">select * from address_book<where><iftest="userId != null">and user_id = #{userId}</if><iftest="phone != null">and phone = #{phone}</if><iftest="isDefault != null">and is_default = #{isDefault}</if></where></select><updateid="update"parameterType="addressBook">update address_book<set><iftest="consignee != null">consignee = #{consignee},</if><iftest="sex != null">sex = #{sex},</if><iftest="phone != null">phone = #{phone},</if><iftest="detail != null">detail = #{detail},</if><iftest="label != null">label = #{label},</if><iftest="isDefault != null">is_default = #{isDefault},</if></set>where id = #{id}</update></mapper>接口文档与需求分析
此时用到了两张表,orders以及order_detail
orders表记录用户下单的完整流程,下单,支付,派送
order_detail表记录下单菜品信息,金额,图片,下单数量
后端需要接收前端的传入的数据,并用传入的地址簿查询其他信息存入orders中,并进行初始设置
Controller
/** * 用户下单 * @param ordersSubmitDTO * @return */@PostMapping("/submit")@ApiOperation("用户下单")publicResult<OrderSubmitVO>submit(@RequestBodyOrdersSubmitDTOordersSubmitDTO){log.info("用户订单信息:{}",ordersSubmitDTO);OrderSubmitVOorderSubmitVO=orderService.submit(ordersSubmitDTO);returnResult.success(orderSubmitVO);}接收前端DTO交给逻辑层处理
Service实现类
逻辑层需要实现的内容:
- 根据传入的DTO中的地址簿信息查询地址簿
- 获取当前用户并获取购物车数据
- 插入订单数据,将前端传入的金额等浅克隆,设置订单支付状态为未支付,状态为等待支付,用当前时间戳设置单号(姑且这么办)设置用户手机号,用户id,用户名称
- 设置订单的基础信息并存入数据库
- 清空购物车
- 封装前端需要返回的内容为VO对象返回
/** * 用户下单 * @param ordersSubmitDTO * @return */publicOrderSubmitVOsubmit(OrdersSubmitDTOordersSubmitDTO){//处理各种业务异常(地址簿为空,购物车数据为空)AddressBookaddressBook=addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());if(addressBook==null){thrownewAddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);}LonguserId=BaseContext.getCurrentId();ShoppingCartshoppingCart=newShoppingCart();shoppingCart.setUserId(userId);List<ShoppingCart>list=shoppingCartMapper.list(shoppingCart);if(list==null||list.isEmpty()){//抛出业务异常thrownewShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);}//插入一条订单数据Ordersorders=newOrders();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);List<OrderDetail>orderDetailList=newArrayList<>();//向订单明细表插入n条数据for(ShoppingCartcart:list){OrderDetailorderDetail=newOrderDetail();BeanUtils.copyProperties(cart,orderDetail);orderDetail.setOrderId(orders.getId());orderDetailList.add(orderDetail);}orderDetailMapper.insertBatch(orderDetailList);//清空购物车shoppingCartMapper.clean(userId);//封装VO对象返回前端returnOrderSubmitVO.builder().id(orders.getId()).orderNumber(orders.getNumber()).orderAmount(orders.getAmount()).orderTime(orders.getOrderTime()).build();}Mapper
批量插入订单基础信息
<insertid="insertBatch">insert into order_detail (name, image, order_id, dish_id, setmeal_id, dish_flavor, amount) VALUES<foreachcollection="orderDetailList"item="od"separator=",">(#{od.name},#{od.image},#{od.orderId},#{od.dishId},#{od.setmealId},#{od.dishFlavor},#{od.amount})</foreach></insert>清空购物车
@Delete("delete from shopping_cart where user_id=#{userId}")voidclean(LonguserId);微信小程序下单
流程简述
1. 初始下单阶段
此处为用户点击去下单确认支付的阶段
- 进入下单:微信用户通过微信小程序发起下单请求。
- 创建订单:小程序向商户系统发送下单指令。
- 返回信息:商户系统处理后,返回订单号等相关信息给小程序。
2. 支付申请与预处理阶段
此处为点击确认支付后阶段
- 申请支付:小程序向商户系统发起微信支付申请。
- 预下单:商户系统调用微信后台的下单接口。
- 获取标识:微信后台返回预支付交易标识给商户系统。
- 签名处理:商户系统对数据进行再次签名,并将支付参数返回给小程序。
3. 用户确认与执行支付阶段
此处为支付完成后阶段
- 确认支付:微信用户在小程序端确认支付。
- 调起支付:小程序调起微信支付功能并请求微信后台执行。
- 返回结果:微信后台将支付结果反馈给小程序。
4. 结果展示与状态更新阶段
此处为支付成功后回显订单阶段
- 结果显示:小程序向用户展示最终的支付结果。
- 后台通知:与此同时,微信后台将支付结果推送给商户系统。
- 更新状态:商户系统根据接收到的结果更新内部订单状态。
接口文档
代码实现
Controller
接收前端传入单号以及支付方式,交付给service处理
/** * 订单支付 * * @param ordersPaymentDTO * @return */@PutMapping("/payment")@ApiOperation("订单支付")publicResult<OrderPaymentVO>payment(@RequestBodyOrdersPaymentDTOordersPaymentDTO)throwsException{log.info("订单支付:{}",ordersPaymentDTO);OrderPaymentVOorderPaymentVO=orderService.payment(ordersPaymentDTO);log.info("生成预支付交易单:{}",orderPaymentVO);returnResult.success(orderPaymentVO);}Service实现类
下单后按照流程此时为调用下单接口,将返回的prepay_id给开发者服务器作为预支付交易会话标识,后端进一步进行签名加密。由于只有企业才可获得mchid,如果实现支付可以将VO按如下方式封装后返回给前端,虽然有内容但是并没有实质内容
/** * 订单支付 * @param ordersPaymentDTO * @return */publicOrderPaymentVOpayment(OrdersPaymentDTOordersPaymentDTO)throwsException{// 当前登录用户idLonguserId=BaseContext.getCurrentId();Useruser=userMapper.getById(userId);// 模拟支付数据OrderPaymentVOvo=newOrderPaymentVO();vo.setNonceStr("testNonceStr");vo.setPaySign("testPaySign");vo.setTimeStamp(String.valueOf(System.currentTimeMillis()));vo.setSignType("RSA");vo.setPackageStr("prepay_id=test");paySuccess(ordersPaymentDTO.getOrderNumber());returnvo;}总结
实现了用户下单,微信支付。在用户下单方面按照需要实现的功能独立实现了大部分内容,但是有一部分内容没有分析出,比如清空购物车;实现微信支付,了解了微信支付流程,对于后端支付有了进一步的认识。最后的支付代码由ai修改为当前形式。
学习了cpolar,用于将本地运行的springboot程序映射到公网域名,可以通过公网URL访问前端
