导入地址簿代码需求分析和设计接口设计表设计address_book 表字段名数据类型说明备注idbigint主键自增user_idbigint用户id逻辑外键consigneevarchar(50)收货人sexvarchar(2)性别phonevarchar(11)手机号province_codevarchar(12)省份编码province_namevarchar(32)省份名称city_codevarchar(12)城市编码city_namevarchar(32)城市名称district_codevarchar(12)区县编码district_namevarchar(32)区县名称detailvarchar(200)详细地址信息具体到门牌号labelvarchar(100)标签公司、家、学校is_defaulttinyint(1)是否默认地址1是 0否代码导入Controller 层AddressBookControllerRestController RequestMapping(/user/addressBook) Api(tags C端地址簿接口) public class AddressBookController{ Autowired 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(); } /** * 根据id查询地址 * param id * return */ 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(){ 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(没有查询到默认地址); } }Service 层AddressBookServicepublic interface AddressBookService{ ListAddressBook list(AddressBook addressBook); void save(AddressBook addressBook); AddressBook getById(Long id); void update(AddressBook addressBook); void setDefault(AddressBook addressBook); void deleteById(Long id); }AddressBookServiceImplService 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 */ public void setDefault(AddressBook addressBook){ //将当前用户的所有地址修改为非默认地址 addressBook.setIsDefault(0); addressBook.setUserId(BaseContext.getCurrentId()); addressBookMapper.updateIsDefaultByUserId(addressBook); //将当前地址改为默认地址 addressBook.setIsDefault(1); addressBookMapper.update(addressBook); } /** * 根据id删除地址 * param id */ public void deleteById(Long id){ addressBookMapper.deleteById(id); } }Mapper 层AddressBookMapperMapper 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); }AddressBookMapper.xml?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 testconsignee ! null consignee #{consignee}, /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 /mapper功能测试代码提交用户下单需求分析和设计产品原型接口设计表设计orders 订单表字段名数据类型说明备注idbigint主键自增numbervarchar(50)订单号statusint订单状态1待付款 2待接单 3已接单 4派送中 5已完成 6已取消user_idbigint用户id逻辑外键address_book_idbigint地址id逻辑外键order_timedatetime下单时间checkout_timedatetime付款时间pay_methodint支付方式1微信支付 2支付宝支付pay_statustinyint支付状态0未支付 1已支付 2退款amountdecimal(10,2)订单金额remarkvarchar(100)备注信息phonevarchar(11)手机号冗余字段addressvarchar(255)详细地址信息冗余字段consigneevarchar(32)收货人冗余字段cancel_reasonvarchar(255)订单取消原因rejection_reasonvarchar(255)拒单原因cancel_timedatetime订单取消时间estimated_delivery_timedatetime预计送达时间delivery_statustinyint配送状态1立即送出 0选择具体时间delivery_timedatetime送达时间pack_amountint打包费tableware_numberint餐具数量tableware_statustinyint餐具数量状态1按餐量提供 0选择具体数量order_detail 订单明细表字段名数据类型说明备注idbigint主键自增namevarchar(32)商品名称冗余字段imagevarchar(255)商品图片路径冗余字段order_idbigint订单id逻辑外键dish_idbigint菜品id逻辑外键setmeal_idbigint套餐id逻辑外键dish_flavorvarchar(50)菜品口味numberint商品数量amountdecimal(10,2)商品单价代码开发设计 DTO 类OrdersSubmitDTOData public class OrdersSubmitDTO implements Serializable{ //地址簿id private Long addressBookId; //付款方式 private int payMethod; //备注 private String remark; //预计送达时间 JsonFormat(shape JsonFormat.Shape.STRING, pattern yyyy-MM-dd HH:mm:ss) private LocalDateTime estimatedDeliveryTime; //配送状态 1立即送出 0选择具体时间 private Integer deliveryStatus; //餐具数量 private Integer tablewareNumber; //餐具数量状态 1按餐量提供 0选择具体数量 private Integer tablewareStatus; //打包费 private Integer packAmount; //总金额 private BigDecimal amount; }设计 VO 类OrderSubmitVOData Builder NoArgsConstructor AllArgsConstructor public class OrderSubmitVO implements Serializable{ //订单id private Long id; //订单号 private String orderNumber; //订单金额 private BigDecimal orderAmount; //下单时间 private LocalDateTime orderTime; }Controller 层OrderController/** * 订单 */ RestController(userOrderController) RequestMapping(/user/order) Slf4j Api(tags C端-订单接口) public class OrderController{ Autowired private OrderService orderService; /** * 用户下单 * param ordersSubmitDTO * return */ PostMapping(/submit) ApiOperation(用户下单) public ResultOrderSubmitVO submit(RequestBody OrdersSubmitDTO ordersSubmitDTO){ log.info(用户下单{},ordersSubmitDTO); OrderSubmitVO orderSubmitVO orderService.submitOrder(ordersSubmitDTO); return Result.success(orderSubmitVO); } }Service 层OrderServicepublic interface OrderService{ /** * 用户下单 * param ordersSubmitDTO * return */ OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO); }OrderServiceImpl/** * 订单 */ Service Slf4j public class OrderServiceImpl implements OrderService{ Autowired private OrderMapper orderMapper; Autowired private OrderDetailMapper orderDetailMapper; Autowired private ShoppingCartMapper shoppingCartMapper; Autowired private AddressBookMapper addressBookMapper; /** * 用户下单 * param ordersSubmitDTO * return */ Transactional public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO){ //异常情况的处理收货地址为空、超出配送范围、购物车为空 AddressBook addressBook addressBookMapper.getById(ordersSubmitDTO.getAddressBookId()); if(addressBook null){ throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL); } Long userId BaseContext.getCurrentId(); ShoppingCart shoppingCart new ShoppingCart(); shoppingCart.setUserId(userId); //查询当前用户的购物车数据 ListShoppingCart shoppingCartList shoppingCartMapper.list(shoppingCart); if(shoppingCartList null || shoppingCartList.size() 0){ throw new AddressBookBusinessException(MessageConstant.SHOPPING_CART_IS_NULL); } //构造订单数据 Orders order new Orders(); BeanUtils.copyProperties(ordersSubmitDTO,order); order.setPhone(addressBook.getPhone()); order.setAddress(addressBook.getDetail()); order.setConsignee(addressBook.getConsignee()); order.setNumber(String.valueOf(System.currentTimeMillis())); order.setUserId(userId); order.setStatus(Orders.PENDING_PAYMENT); order.setPayStatus(Orders.UN_PAID); order.setOrderTime(LocalDateTime.now()); //向订单表插入1条数据 orderMapper.insert(order); //订单明细数据 ListOrderDetail orderDetailList new ArrayList(); for(ShoppingCart cart : shoppingCartList){ OrderDetail orderDetail new OrderDetail(); BeanUtils.copyProperties(cart,orderDetail); orderDetail.setOrderId(order.getId()); orderDetailList.add(orderDetail); } //向明细表插入n条数据 orderDetailMapper.insertBatch(orderDetailList); //清理购物车中的数据 shoppingCartMapper.deleteByUserId(userId); //封装返回结果 OrderSubmitVO orderSubmitVO OrderSubmitVO.builder() .id(order.getId()) .orderNumber(order.getNumber()) .orderAmount(order.getAmount()) .orderTime(order.getOrderTime()) .build(); return orderSubmitVO; } }Mapper 层OrderMapperMapper public interface OrderMapper{ /** * 插入订单数据 * param order */ void insert(Orders order); }OrderDetailMapperMapper public interface OrderDetailMapper{ /** * 批量插入订单明细数据 * param orderDetails */ void insertBatch(ListOrderDetail orderDetails); }OrderMapper.xml?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.OrderMapper insert idinsert parameterTypeOrders useGeneratedKeystrue keyPropertyid insert into orders (number, status, user_id, address_book_id, order_time, checkout_time, pay_method, pay_status, amount, remark, phone, address, consignee, estimated_delivery_time, delivery_status, pack_amount, tableware_number, tableware_status) values (#{number}, #{status}, #{userId}, #{addressBookId}, #{orderTime}, #{checkoutTime}, #{payMethod}, #{payStatus}, #{amount}, #{remark}, #{phone}, #{address}, #{consignee}, #{estimatedDeliveryTime}, #{deliveryStatus}, #{packAmount}, #{tablewareNumber}, #{tablewareStatus}) /insert /mapperOrderDetailMapper.xml?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.OrderDetailMapper insert idinsertBatch parameterTypelist insert into order_detail (name, order_id, dish_id, setmeal_id, dish_flavor, number, amount, image) values foreach collectionorderDetails itemod separator, (#{od.name},#{od.orderId},#{od.dishId},#{od.setmealId},#{od.dishFlavor}, #{od.number},#{od.amount},#{od.image}) /foreach /insert /mapper功能测试代码提交订单支付微信支付介绍实现微信支付需要注册微信支付的一个商户号该商户号是必须要有一家企业并且有正规的营业执照而个人不具备这种资质只做了解微信支付的流程微信支付产品https://pay.weixin.qq.com/static/product/product_index.shtml微信支付接入流程微信支付相关接口JSAPI 下单商户系统调用该接口在微信支付服务后台生成预支付交易单微信小程序调起支付通过 JSAPI 下单接口获取到发起支付的必要参数然后使用微信支付提供的小程序方法调起小程序支付准备工作保证数据安全微信支付的关键步骤生成预支付交易单支付成功后微信后台推送消息为保证这两个接口数据的安全性需要提前准备相应一些文件完成数据加密解密获取微信支付平台证书、商户私钥文件调用商户系统微信后台会通过 HTTP 请求推送支付结果到商户系统但本地商户系统是局域网 IP微信后台无法访问可用 cpolar 做内网穿透生成公网可访问的临时域名让微信后台能正常调用商户系统Cpolar下载地址https://dashboard.cpolar.com/get-started指定 authtoken复制 authtoken执行命令获取临时域名执行命令获取域名验证临时域名有效性代码导入修改了部分代码以实现功能微信支付相关配置application-dev.ymlsky: wechat: appid: wxb057652bd9e3ec4d secret: 9b2be4b9348f99444565c57d9e2ca7e2 mchid : 1561414331 mchSerialNo: 4B3B3DC35414AD50B1B755BAF8DE9CC7CF407606 privateKeyFilePath: D:\apiclient_key.pem apiV3Key: CZBK51236435wxpay435434323FFDuv3 weChatPayCertFilePath: D:\wechatpay_166D96F876F45C7D07CE98952A96EC980368ACFC.pem notifyUrl: https://www.weixin.qq.com/wxpay/pay.php refundNotifyUrl: https://www.weixin.qq.com/wxpay/pay.phpapplication.ymlsky: wechat: appid: ${sky.wechat.appid} secret: ${sky.wechat.secret} mchid : ${sky.wechat.mchid} mchSerialNo: ${sky.wechat.mchSerialNo} privateKeyFilePath: ${sky.wechat.privateKeyFilePath} apiV3Key: ${sky.wechat.apiV3Key} weChatPayCertFilePath: ${sky.wechat.weChatPayCertFilePath} notifyUrl: ${sky.wechat.notifyUrl} refundNotifyUrl: ${sky.wechat.refundNotifyUrl}WeChatPropertiesComponent ConfigurationProperties(prefix sky.wechat) Data public class WeChatProperties{ private String appid; //小程序的appid private String secret; //小程序的秘钥 private String mchid; //商户号 private String mchSerialNo; //商户API证书的证书序列号 private String privateKeyFilePath; //商户私钥文件 private String apiV3Key; //证书解密的密钥 private String weChatPayCertFilePath; //平台证书 private String notifyUrl; //支付成功的回调地址 private String refundNotifyUrl; //退款成功的回调地址 }Controller 层OrderController/** * 订单支付 * * param ordersPaymentDTO * return */ PutMapping(/payment) ApiOperation(订单支付) public ResultOrderPaymentVO payment(RequestBody OrdersPaymentDTO ordersPaymentDTO) throws Exception{ log.info(订单支付{}, ordersPaymentDTO); OrderPaymentVO orderPaymentVO orderService.payment(ordersPaymentDTO); log.info(生成预支付交易单{}, orderPaymentVO); orderService.paySuccess(ordersPaymentDTO.getOrderNumber()); return Result.success(orderPaymentVO); }PayNotifyControllerpackage com.sky.controller.nofity; /** * 支付回调相关接口 */ RestController RequestMapping(/notify) Slf4j public class PayNotifyController{ Autowired private OrderService orderService; Autowired private WeChatProperties weChatProperties; /** * 支付成功回调 * * param request */ RequestMapping(/paySuccess) public void paySuccessNotify(HttpServletRequest request, HttpServletResponse response) throws Exception{ //读取数据 String body readData(request); log.info(支付成功回调{}, body); //数据解密 String plainText decryptData(body); log.info(解密后的文本{}, plainText); JSONObject jsonObject JSON.parseObject(plainText); String outTradeNo jsonObject.getString(out_trade_no);//商户平台订单号 String transactionId jsonObject.getString(transaction_id);//微信支付交易号 log.info(商户平台订单号{}, outTradeNo); log.info(微信支付交易号{}, transactionId); //业务处理修改订单状态、来单提醒 orderService.paySuccess(outTradeNo); //给微信响应 responseToWeixin(response); } /** * 读取数据 * * param request * return * throws Exception */ private String readData(HttpServletRequest request) throws Exception{ BufferedReader reader request.getReader(); StringBuilder result new StringBuilder(); String line null; while((line reader.readLine()) ! null){ if(result.length() 0){ result.append(\n); } result.append(line); } return result.toString(); } /** * 数据解密 * * param body * return * throws Exception */ private String decryptData(String body) throws Exception{ JSONObject resultObject JSON.parseObject(body); JSONObject resource resultObject.getJSONObject(resource); String ciphertext resource.getString(ciphertext); String nonce resource.getString(nonce); String associatedData resource.getString(associated_data); AesUtil aesUtil new AesUtil(weChatProperties.getApiV3Key().getBytes(StandardCharsets.UTF_8)); //密文解密 String plainText aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext); return plainText; } /** * 给微信响应 * param response */ private void responseToWeixin(HttpServletResponse response) throws Exception{ response.setStatus(200); HashMapObject, Object map new HashMap(); map.put(code, SUCCESS); map.put(message, SUCCESS); response.setHeader(Content-type, ContentType.APPLICATION_JSON.toString()); response.getOutputStream().write(JSONUtils.toJSONString(map).getBytes(StandardCharsets.UTF_8)); response.flushBuffer(); } }Service 层OrderService/** * 订单支付 * param ordersPaymentDTO * return */ OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception; /** * 支付成功修改订单状态 * param outTradeNo */ void paySuccess(String outTradeNo);OrderServiceImplAutowired private UserMapper userMapper; Autowired private WeChatPayUtil weChatPayUtil; /** * 订单支付 * * param ordersPaymentDTO * return * throws Exception */ public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception{ //当前登录用户id Long userId BaseContext.getCurrentId(); User user userMapper.getById(userId); //调用微信支付接口生成预支付交易单 /*JSONObject jsonObject weChatPayUtil.pay( ordersPaymentDTO.getOrderNumber(), //商户订单号 new BigDecimal(0.01), //支付金额单位 元 苍穹外卖订单, //商品描述 user.getOpenid() //微信用户的openid );*/ JSONObject jsonObject new JSONObject(); if(jsonObject.getString(code) ! null jsonObject.getString(code).equals(ORDERPAID)){ throw new OrderBusinessException(该订单已支付); } OrderPaymentVO vo jsonObject.toJavaObject(OrderPaymentVO.class); vo.setPackageStr(jsonObject.getString(package)); return vo; } /** * 支付成功修改订单状态 * * param outTradeNo */ public void paySuccess(String outTradeNo){ //当前登录用户id Long userId BaseContext.getCurrentId(); //根据订单号查询当前用户的订单 Orders ordersDB orderMapper.getByNumberAndUserId(outTradeNo, userId); //根据订单id更新订单的状态、支付方式、支付状态、结账时间 Orders orders Orders.builder() .id(ordersDB.getId()) .status(Orders.TO_BE_CONFIRMED) .payStatus(Orders.PAID) .checkoutTime(LocalDateTime.now()) .build(); orderMapper.update(orders); }Mapper 层OrderMapper/** * 根据订单号和用户id查询订单 * param orderNumber * param userId */ Select(select * from orders where number #{orderNumber} and user_id #{userId}) Orders getByNumberAndUserId(String orderNumber, Long userId); /** * 修改订单信息 * param orders */ void update(Orders orders);UserMapper/** * 根据userId查询用户 * param userId * return */ Select(select * from user where id #{userId}) User getById(Long userId);OrderMapper.xmlupdate idupdate parameterTypecom.sky.entity.Orders update orders set if testcancelReason ! null and cancelReason! cancel_reason#{cancelReason}, /if if testrejectionReason ! null and rejectionReason! rejection_reason#{rejectionReason}, /if if testcancelTime ! null cancel_time#{cancelTime}, /if if testpayStatus ! null pay_status#{payStatus}, /if if testpayMethod ! null pay_method#{payMethod}, /if if testcheckoutTime ! null checkout_time#{checkoutTime}, /if if teststatus ! null status #{status}, /if if testdeliveryTime ! null delivery_time #{deliveryTime} /if /set where id #{id} /update功能测试代码提交