2026/4/2 7:10:39
网站建设
项目流程
wordpress主题原创,网站标题优化 英文,网站做百度推广,微网站开发一般费用多少钱一、回顾与概览第七天我们使用SpringCache进行缓存商品的操作#xff0c;并将购物车这个核心模块编写完成。今天需要完成用户下单和订单支付两个核心模块#xff0c;前者注重理解Service层逻辑#xff0c;后者理解调用微信支付的时序图。二、用户下单1.前置地址簿功能导入并将购物车这个核心模块编写完成。今天需要完成用户下单和订单支付两个核心模块前者注重理解Service层逻辑后者理解调用微信支付的时序图。二、用户下单1.前置地址簿功能导入1产品原型和接口文档通过分析接口文档和产品原型可以大致清楚地址簿功能的组成查询用户所有地址、新增地址、修改地址、设置默认地址包含取消功能、查询默认地址、删除地址。上述功能接口写下来与之前的并没有太大区别因此直接导入作为用户下单的前置功能模块。2Controller层package com.sky.controller.user; import com.sky.context.BaseContext; import com.sky.entity.AddressBook; import com.sky.result.Result; import com.sky.service.AddressBookService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; RestController RequestMapping(/user/addressBook) Api(tags C端地址簿接口) public class AddressBookController { Autowired private AddressBookService addressBookService; /** * 查询当前登录用户的所有地址信息 * * return */ GetMapping(/list) ApiOperation(查询当前登录用户的所有地址信息) public ResultListAddressBook list() { AddressBook addressBook new AddressBook(); addressBook.setUserId(BaseContext.getCurrentId()); ListAddressBook list addressBookService.list(addressBook); return Result.success(list); } /** * 新增地址 * * param addressBook * return */ PostMapping ApiOperation(新增地址) public Result save(RequestBody AddressBook addressBook) { addressBookService.save(addressBook); return Result.success(); } GetMapping(/{id}) ApiOperation(根据id查询地址) public ResultAddressBook getById(PathVariable Long id) { AddressBook addressBook addressBookService.getById(id); return Result.success(addressBook); } /** * 根据id修改地址 * * param addressBook * return */ PutMapping ApiOperation(根据id修改地址) public Result update(RequestBody AddressBook addressBook) { addressBookService.update(addressBook); return Result.success(); } /** * 设置默认地址 * * param addressBook * return */ PutMapping(/default) ApiOperation(设置默认地址) public Result setDefault(RequestBody AddressBook addressBook) { addressBookService.setDefault(addressBook); return Result.success(); } /** * 根据id删除地址 * * param id * return */ DeleteMapping ApiOperation(根据id删除地址) public Result deleteById(Long id) { addressBookService.deleteById(id); return Result.success(); } /** * 查询默认地址 */ GetMapping(default) ApiOperation(查询默认地址) public ResultAddressBook getDefault() { //SQL:select * from address_book where user_id ? and is_default 1 AddressBook addressBook new AddressBook(); addressBook.setIsDefault(1); addressBook.setUserId(BaseContext.getCurrentId()); ListAddressBook list addressBookService.list(addressBook); if (list ! null list.size() 1) { return Result.success(list.get(0)); } return Result.error(没有查询到默认地址); } }3Service层package com.sky.service.impl; import com.sky.context.BaseContext; import com.sky.entity.AddressBook; import com.sky.mapper.AddressBookMapper; import com.sky.service.AddressBookService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; Service Slf4j public class AddressBookServiceImpl implements AddressBookService { Autowired private AddressBookMapper addressBookMapper; /** * 条件查询 * * param addressBook * return */ public ListAddressBook list(AddressBook addressBook) { return addressBookMapper.list(addressBook); } /** * 新增地址 * * param addressBook */ public void save(AddressBook addressBook) { addressBook.setUserId(BaseContext.getCurrentId()); addressBook.setIsDefault(0); addressBookMapper.insert(addressBook); } /** * 根据id查询 * * param id * return */ public AddressBook getById(Long id) { AddressBook addressBook addressBookMapper.getById(id); return addressBook; } /** * 根据id修改地址 * * param addressBook */ public void update(AddressBook addressBook) { addressBookMapper.update(addressBook); } /** * 设置默认地址 * * param addressBook */ Transactional public void setDefault(AddressBook addressBook) { // 补充取消当前地址为默认地址如果当前地址为默认地址1那么就设置为0 AddressBook addressBook1 addressBookMapper.getById(addressBook.getId()); if (addressBook1.getIsDefault() 1) { addressBook.setIsDefault(0); addressBookMapper.update(addressBook); return; } //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 */ public void deleteById(Long id) { addressBookMapper.deleteById(id); } }4Mapper层package com.sky.mapper; import com.sky.entity.AddressBook; import org.apache.ibatis.annotations.*; import java.util.List; Mapper public interface AddressBookMapper { /** * 条件查询 * param addressBook * return */ ListAddressBook list(AddressBook addressBook); /** * 新增 * 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})) void insert(AddressBook addressBook); /** * 根据id查询 * param id * return */ Select(select * from address_book where id #{id}) AddressBook getById(Long id); /** * 根据id修改 * param addressBook */ void update(AddressBook addressBook); /** * 根据 用户id修改 是否默认地址 * param addressBook */ Update(update address_book set is_default #{isDefault} where user_id #{userId}) void updateIsDefaultByUserId(AddressBook addressBook); /** * 根据id删除地址 * param id */ Delete(delete from address_book where id #{id}) void deleteById(Long id); }?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.sky.mapper.AddressBookMapper select idlist parameterTypeAddressBook resultTypeAddressBook select * from address_book where if testuserId ! null and user_id #{userId} /if if testphone ! null and phone #{phone} /if if testisDefault ! null and is_default #{isDefault} /if /where /select update idupdate parameterTypeaddressBook update address_book set if testcityCode ! null city_code #{cityCode}, /if if testcityName ! null city_name #{cityName}, /if if testconsignee ! null consignee #{consignee}, /if if testdistrictCode ! null district_code #{districtCode}, /if if testdistrictName ! null district_name #{districtName}, /if if testprovinceCode ! null province_code #{provinceCode}, /if if testprovinceName ! null province_name #{provinceName}, /if if testsex ! null sex #{sex}, /if if testphone ! null phone #{phone}, /if if testdetail ! null detail #{detail}, /if if testlabel ! null label #{label}, /if if testisDefault ! null is_default #{isDefault}, /if /set where id #{id} /update /mapper2.需求分析与接口文档接口文档对应前端请求响应数据即小程序下单流程界面第二张展示的数据涉及orders和order_detail两张表两张表是一对多关系前端请求点击去支付调用后端接口产品原型小程序下单流程界面基于我们的最终目的是把用户订单所提供的信息插入到orders和order_detail两张表中又因为请求参数中所传的参数远远达不到表中字段要求因此我们需要进行补充字段后进行插入。3.Controller层直接调用Service层最终返回OrderSubmitVO传参json格式加上RequestBody注解。4.Service层1构造订单数据首先先处理Orders表的插入那先new一个Orders类然后调用BeanUtils进行属性拷贝。接着就是逐个set缺失字段了。订单编号使用当前系统时间保证唯一性单线程全部由数字组成包含字母也可以考虑使用UUID订单状态设置为常量待付款用户Id从ThreadLocal中获取下单时间设置为当前时间支付状态设置为常量未支付手机地址、详细地址、收货人这三个字段在AddressBook表中请求参数中传了AddressBookId因此可以调用AddressBookMapper根据Id查地址然后判断如果地址为空抛出自定义异常即可。下单人字段在User表中可以通过ThreadLocal中的userId查User表获取到用户名称查出来的user也需要判断如果为空抛出自定义异常用户未登录userId不存在即ThreadLocal中没有存入拦截器未拦截。最后调用OrdersMapper的insert方法传入补充好字段的Orders对象插入表中即可。2构造订单明细数据之前已经分析过orders表和order_detail表两张表是一对多关系因此先构造一个List里面存储多个OrderDetail对象另外分析order_detail表和shopping_cart表可以发现两张表字段基本上是一样的因此只需要根据userId查询该用户购物车数据即可然后把购物车里面的数据对应插入到order_detail表中即可这也符合购物时把购物车商品清空移动到订单上的业务逻辑。对于查出来的ListShoppingCart也需要判断如果为空抛出自定义异常。然后就可以遍历这个List每次遍历都new一个OrderDeatil对象把ShoppingCart属性拷贝到OrderDeatil中但需要注意id属性不能拷贝避免出现重复id字段BeanUtils的copyProperties的第三个参数ignoreProperties可以设置忽略字段。此外由于orders表和order_detail表两张表是一对多关系每行订单明细数据还要管理订单id之后才可以把封装好的对象add进List中最后调用orderDetailMapper的insertBatch方法批量插入List表中的数据。3清空购物车成功下单后购物车里面的数据就被清空了直接调用shoppingCartMapper的delete方法即可传参userId只清空该用户的购物车数据。4返回OrderSubmitVO对象观察小程序下单流程第二张图片包含了订单ID订单编号订单总额下单时间四个字段OrderSubmitVO就是包含了这四个字段需要将对应属性都补充后返回给前端。5.Mapper层AddressBookMapper的getById方法查询地址表UserMapper的selectById方法查询用户表ShoppingCartMapper的select方法查询购物车OrdersMapper的insert方法插入订单数据OrdersDetailMapper的insertBatch方法插入订单明细数据ShoppingCartMapper的delete方法清空购物车三、订单支付1.微信小程序支付时序图2.业务逻辑修改点击确认支付就会自动调用开发者服务器后端的payment接口。这一步是在Service层主要是开发者服务器调用第三方微信下单接口的接口文档最终返回prepay_id给开发者服务器作为预支付交易会话标识后端则需要对该标识进一步加密最终返回给小程序端支付参数OrderPaymentVO。但是因为在项目中无法获取有效的mchid等请求参数所以没法返回有效的OrderPaymentVO真正实现调用微信支付所以需要修改Service层逻辑直接在payment方法中调用paySuccess方法修改数据库中Orders表的订单状态参数订单编号在ordersPaymentDTO里面存在返回空的OrderPaymentVO保证程序正常走完即可。由于后端无法返回正确的支付参数OrderPaymentVO所以小程序端也无法调用微信支付因此把相应代码注释直接跳转支付成功页面即可。3.实现效果点击支付后显示成功下单数据库中订单状态改为待接单。四、总结今天主要完成了用户下单和订单支付两个功能模块感觉有了之前购物车模块编写的经验用户下单写起来也不是很复杂订单支付这里也是调用一些第三方接口类似操作不过因为配置信息问题没法真正实现微信支付调用只是进行了个模拟所以导入的PayNotifyController这些东西都没用上里面的一些加密逻辑也不怎么了解新学了个cpolar技术也没用上这玩意可以让第三方接口服务重定向到开发者服务器上可以用虚拟的网站地址而不是localhost又定向到自己服务器可以在开发阶段调试使用。