支付頁面
接口文檔
@Operation(summary="獲取訂單信息")
@GetMapping("auth/{orderId}")
public Reuslt<OrderInfo> getOrderInfo(@Parameter(name="orderId",description="訂單id",required=true) @PathVaariable Long orderId){OrderInfo orderInfo = orderInfoService.getOrderInfo(orderId);return Reuslt.build(orderInfo,ResultCode.SUCCESS);
}
@Override
public OrderInfo getOrderInfo(Long orderId){return orderInfoMapper.getById(orderId);
}
//mapper
OrderInfo getById(Long orderId);
<select id="getById"resultType="com.xxx.OrderInfo" >select *from order_infowhere id=#{orderId}</select>
不經過購物車,直接購買
@Operation(summary="立即購買")
@GetMapping("auth/buy/{skuId}")
public Result buy(@PathVariable Long skuId){TradeVo tradeVo = orderInfoService.buy(skuId);return Result.build(tredeVo,ResultCodeEnum.SUCCESS);
}
@Override
public TradeVo buy(Long skuId){List<OrderItem> orderItemList = new ArrayList<>();ProductSku productSku = productFeignClient.getBySkuId(skuId);OrderIntem orderItem = new OrderItem();orderItem.setSkuId(skuId);orderItem.setSkuName(productSku.getSkuName());orderItem.setSkuNum(1);orderItem.setSkuPrice(productSku.getSalePrice());orderItem.setThumbImg(productSku.getThumbImg());orderItemList.add(orderItem);TradeVo tradeVo = new TradeVo();trade.setOrderItemList(orderItemList);trade.setTotalAmount(productSku.getSalePrice());return tradeVo;
}
查詢訂單
@Operation(summary="獲取訂單分頁列表")
@GetMapping("auth/{page}/{limit}")
public Result<PageInfo<OrderInfo>> list(@Parameter(name="page",description="當前頁碼",required=true)@PathVariable Integer page,@Parameter(name="limit",description="每頁記錄數",required=true)@PathVariable Integer limit,@Parameter(name="orderStatus",description="訂單狀態",required=false)@RequestParam(required=false,defaultValue="") Integer orderStatus){PageInfo<OrderInfo> pageInfo = orderInfoService.findUserPage(page,limit,orderStatus);return Result.build(pageInfo,ResultCodeEnum.SUCCESS);
}
@Override
public PageInfo<OrderInfo> findOrderPage(Integer page,Integer limit,Integer orderStatus){PageHelper.startPage(page,limit);//查詢訂單信息Long userId = AuthContextUtil.getUserInfo().getId();List<OrderItem> orderInfoList = orderInfoMapper.findUserPage(userId,orderStatus);//查詢訂單里所有的訂單項orderInfoList.forEach(orderInfo -> {//訂單id查詢訂單里面的訂單項List<OrderItem> orderItemList = orderItemMapper.findByOrderId(orderInfo.getId());orderInfo.setOrderItemList(orderItemList);});return new PageInfo<>(orderInfoList);
}
===================================================================================
支付寶支付
通過營業執照進行開通
獲取的參數
①、創建模塊service-pay
配置文件、啟動類……
spring:profiles:active: devserver:port:
spring:application:name:cloud:nacos:discovery:server-addr: localhost:8848datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl:username:password:data:redis:host: localhostport: 6379
mybatis:config-localtion: classpath:mybatis-config.xmlmapper-location: classpath:mapper/*/*.xml
②、保存支付記錄
public interface PaymetInfoService{PaymentInfo savePaymentInfo(String orderNo);
}
@Service
public class PaymentInfoService implements PaymentInfoService{@Autowiredprivate PaymentInfoMapper paymentInfoMapper; @Overridepublic PaymentInfo savePaymentInfo(String orderNo){PaymentInfo paymentInfo = paymentInfoMapper.getByOrderNo(orderNo);if(paymentInfo==null){//如果支付記錄不存在,則遠程調用訂單信息OrderInfo orderInfo = orderFeignClient.getOrderInfoByOrderNo(orderNo).getData();paymentInfo = new PaymentInfo();paymentInfo.setUserId(orderInfo.getUserId());paymentInfo.setPayType(orderInfo.getPayType());String content = "";for(OrderItem item:orderInfo.getOrderItemList()){content += item.getSkuName() + "";}paymentInfo.setContent(content);paymentInfo.setAmount(orderInfo.getTotalAmount());paymentInfo.setOrderNo(orderNo);paymentInfoMapper.save(paymentInfo);}return paymentInfo;}
}
@Mapper
public interface PaymentInfoMapper{PaymentInfo getByOrderNo(String orderNo);void save(PaymentInfo paymentInfo);
}
<sql id="columns">id,user_id,order_no,pay_type,out_trade_no,amount,content,payment_status,callback_time,callback_content
</sql><select id="getByOrderNo" resultMap="paymentInfoMap">select <include refid="colums"></include>from payment_infowhere order_no = #{orderNo}
</select><insert id="save" useGeneratedKeys="true" keyProperty="id">insert into payment_info(id,user_id,order_no,pay_type,out_tread_no,amount,coutent,payment_status,)
</insert>
③、支付接口
Ⅰ、service-pay模塊中添加alipay-sdk依賴
Ⅱ、application-alipay.yml文件,添加配置
Ⅲ、application-dev.yml配置文件需要引入application-alipay.yml
spring:config:import: application-alipay.yml
Ⅳ、讀取配置文件
@Data
@Configuration(prefix="spzx.alipay")
public class AlipayProperties{//屬性名必需和配置文件中的保持一致private String alipayUrl;private String appPrivateKey;public String alipayPublicKey;private String appId;public String returnPaymetUrl;public String notifyPaymentUrl;public final static String format="json";public final static String charset="utf-8";public final static String sign_type="RAS2";
}
Ⅴ、啟動類添加注解@EnableConfigurationProperties(value={AlipayProperties.class})
④、配置發送請求的核心對象AlipayClient
@Configuration
public class AlipayConfiguration{@Autowiredprivate AlipayProperties alipayProperties;@Beanpublic AlipayClient alipayClient(){AlipayClient alipayClient = new DefaultAlipayClient(alipayProperties.getAlipayUrl(),alipayProperties.getAppPrivateKey(),alipayProperties.format,alipayProperties.charset,alipayProperties.getAlipayPublicKey(),alipayProperties.sign_type);return alipayClient;}
}
⑤、返回支付寶支付頁面
@Controller
@RequestMapping()
public class AlipayController{@Autowiredprivate AlipayService alipayService;@Operation(summary="支付寶下單")@GetMapping("submitAlipay/{orderNo}")public Result<String> submitAliPay(@Parameter(name="orderNo",description="訂單號",required=true),@PathVariable(value="orderNo") String orderNo){String form = aliapyService.submitAlipay(orderNo);//返回表單頁面return Result.build(form,ResultCodeEnum.SUCCESS);}
}
@Override
public String submitAlipay(String orderNo){//保存支付記錄PaymentInfo payementInfo = paymentInfoService.savePaymentInfo(orderNo);//調用支付寶服務接口封裝參數AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//同步回調alipayRequest.setReturnUrl(alipayProperties.getReturnPaymentUrl());//異步回調alipayRequest.setNotifyUrl(alipayProperties.getNotifyPaymentUrl());//準備請求參數HashMap<String,Object> map = new HashMap<>();map.put("out_trade_no",paymentInfo.getOrderNo());map.put("product_code","QUICK_WAP_WAY");map.put("total_amount",paymentInfo.getAmount());//map.put("total_amount",new BigDecimal("0.01")); 為了便于測試map.put("subject",paymentInfo.getContent());alipayRequest.setBizContent(JSON.toJSONString(map));try{//發送請求AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipayRequest);if(response.isSuccess()){log.info("調用成功");String form = response.getBody();//返回支付頁面return form;}else{log.info("調用失敗");throw new GuiguException(ResultCodeEnum.DATA_ERROR);}}catch(AlipayApiException e){throw new RuntimeException(e);}}
⑥、完成支付
- 內網穿透,方便用來開發測試
- 支付成功之后到達的頁面:修改自定義的頁面
- 本地的接口路徑:修改為內網穿透綁定到后端網關接口贈送的域名地址
@Operation(summary="支付寶異步回調")
@ReqeustMapping("callback/notify")//該路徑和配置文件中的notify_payment_url
@ResponseBody
public String alipayNotify(@RequestParam Map<String,String> paramMap,HttpServletRequest request){log.info("AlipayController...alipayNotify方法執行了");boolean signVerified = false;//調用SDK驗證簽名(驗證是否是支付寶傳遞過來)try{signVerified = AlipaySignature.rsaCheckVl(paramMap,alipayProperties.getAlipayPublicKey(),AlipayProperties.charset,AlipayProperties.sign_type);}catch(AlipayApiException e){e.printStackTrace();}//交易狀態String trade_status = paramMap.get("trade_status");if(signVerified){//進行二次校驗if("TRADE_SUCCESS".equals(trade_status)||"TRADE_FINISHED".equals(trade_status)){//正常的支付成功,更新交易記錄狀態paymentInfoService.updatePaymentStatus(paraMap,2);return "success";}}else{//驗簽失敗,記錄異常日志return "failture";}
}
//支付狀態的更新
@Override
public void updatePaymentStatus(Map<String,String> map){//根據訂單編號查詢支付記錄信息PaymentInfo paymentInfo = paymentInfoMapper.getByOrderNo(map.get("out_trade_no"));//如果支付記錄已經完成,不需要更新if(paymentInfo.getPaymentStatus()==1){return;}//沒有完成才更新paymentInfo.setPaymentStatus(1);paymentInfo.setOutTradeNo(map.get("trade_no"));paymentInfo.setCallbackTime(new Date());paymentInfo.set.CallbackContent(JSON.toJSONString(map));paymentInfoMapper.updatePaymentInfo(paymentInfo);//遠程調用,更新訂單模塊(根據訂單編號修改)orderFeignClient.updateOorderStatus(paymentInfo.getOrderNo());//更新sku商品銷售
}
配置內網穿透
- 本質上就是因為無法直接調用本地服務,所以通過內網穿透便于第三方服務通過域名來調用本地服務
- ngrok工具:https://ngrok.cc/login/register 注冊用戶
- 完成實名認證
- 開通隧道管理
- 綁定本地服務開發者的service-gateway網關模塊,獲取贈送的域名
- 復制隧道id,下載客戶端工具windows_amd64zip