【业务功能篇104】 补充【业务功能篇99】微服务-springcloud-springboot-电商订单模块--整合支付

在前面我们业务功能篇98-99中,我们介绍了电商项目中的订单模块服务,那么最后就是需要进行支付动作,那么我们这里就通过订阅第三方平台支付宝的支付调用接口功能,来进一步完成订单提交后的支付动作,支付宝的接口使用可以登录官网开发指南详情去了解

SDK依赖引入

在我们对应需要进行支付调用的订单服务中的pom文件加入依赖,其他服务不涉及的不需要加

XML 复制代码
        <!-- 支付宝SDK -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.31.12.ALL</version>
        </dependency>

配置支付宝的配置文件类

  • 根据支付宝的接口使用方式,传递对应订单封装类对象,进行支付操作,并且还有同步回调地址,在支付完成之后自动跳转到我们指定页面
  • 回调地址:public static String return_url = "http://order.msb.com/orderPay/returnUrl"; 指定到该接口,该接口会进行支付完成后需要的操作,比如修改订单的状态为已完成,发货状态为待发货等等.. 然后return指定的html订单详情页面list.html
java 复制代码
/**
 * 支付宝的配置文件
 */
//@ConfigurationProperties(prefix = "alipay")
@Component
@Data
public class AlipayTemplate {

    // 商户appid 沙箱账号: tklalf8880@sandbox.com
    public static String APPID = "2021000121601310";
    // 私钥 pkcs8格式的
    public static String RSA_PRIVATE_KEY = "xx";
    // 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String notify_url = "http://order.msb.com/payed/notify";
    // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
    public static String return_url = "http://order.msb.com/orderPay/returnUrl";
    // 请求网关地址
    public static String URL = "https://openapi.alipaydev.com/gateway.do";
    // 编码
    public static String CHARSET = "UTF-8";
    // 返回格式
    public static String FORMAT = "json";
    // 支付宝公钥
    public static String ALIPAY_PUBLIC_KEY = "xx";
    // 日志记录目录
    public static String log_path = "/log";
    // RSA2
    public static String SIGNTYPE = "RSA2";

    public String pay(PayVo payVo){
        // SDK 公共请求类,包含公共请求参数,以及封装了签名与验签,开发者无需关注签名与验签
        //调用RSA签名方式
        AlipayClient client = new DefaultAlipayClient(URL,
                APPID,
                RSA_PRIVATE_KEY,
                FORMAT,
                CHARSET,
                ALIPAY_PUBLIC_KEY,
                SIGNTYPE);
        AlipayTradeWapPayRequest alipay_request=new AlipayTradeWapPayRequest();

        // 封装请求支付信息
        AlipayTradeWapPayModel model=new AlipayTradeWapPayModel();
        model.setOutTradeNo(payVo.getOut_trader_no());
        model.setSubject(payVo.getSubject());
        model.setTotalAmount(payVo.getTotal_amount());
        model.setBody(payVo.getBody());
        model.setTimeoutExpress("5000");
        model.setProductCode("11111");
        alipay_request.setBizModel(model);
        // 设置异步通知地址
        alipay_request.setNotifyUrl(notify_url);
        // 设置同步地址
        alipay_request.setReturnUrl(return_url);

        // form表单生产
        String form = "";
        try {
            // 调用SDK生成表单
            form = client.pageExecute(alipay_request).getBody();
            return form;
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return  null;
    }
}

支付接口

controller层

复制代码
payOrder:在订单页面中,点击 支付宝发起支付请求的方法
复制代码
orderPay:支付完成之后,会同步回调到订单详情的方法,同时执行支付完成后需要的动作,比如修改订单状态为 关闭, 发货状态为待发货等等..
java 复制代码
@Controller
public class OrderWebController {

    @Autowired
    private OrderService orderService;

    @Autowired
    AlipayTemplate alipayTemplate;

 /**
     * 获取订单相关信息
     * 然后跳转到支付页面  tklalf8880@sandbox.com
     * @param orderSn
     * @return
     */
    @GetMapping(value = "/payOrder",produces = "text/html")
    @ResponseBody
    public String payOrder(@RequestParam("orderSn") String orderSn){
        // 根据订单编号查询出相关的订单信息,封装到PayVO中
        PayVo payVo = orderService.getOrderPay(orderSn);
        String pay = alipayTemplate.pay(payVo);
        //System.out.println(pay);
        return pay;
    }

    @GetMapping("/orderPay/returnUrl")
    public String orderPay(@RequestParam(value = "orderSn",required = false) String orderSn,
                           @RequestParam(value = "out_trade_no",required = false) String out_trade_no){
        // TODO 完成相关的支付操作
        System.out.println("orderSn = " + orderSn);
        if(StringUtils.isNotBlank(orderSn)){
            orderService.handleOrderComplete(orderSn);

        }else{
            //orderService.updateOrderStatus(out_trade_no,OrderConstant.OrderStateEnum.TO_SEND_GOODS.getCode());
            orderService.handleOrderComplete(out_trade_no);
        }
        return "list";
    }

service层

java 复制代码
    @Override
//封装订单号对应的信息 返回给支付宝配置类的方法
    public PayVo getOrderPay(String orderSn) {
        // 根据订单号查询相关的订单信息
        OrderEntity orderEntity = this.getBaseMapper().getOrderByOrderSn(orderSn);
        // 通过订单信息封装 PayVO对象
        PayVo payVo = new PayVo();
        payVo.setOut_trader_no(orderSn);
        payVo.setTotal_amount(orderEntity.getTotalAmount().setScale(2, RoundingMode.UP).toString());
        // 订单名称和订单描述
        payVo.setSubject(orderEntity.getOrderSn());
        payVo.setBody(orderEntity.getOrderSn());
        return payVo;
    }


    @Override
    //支付完成之后,修改订单状态
    public void handleOrderComplete(String orderSn) {
        // 1.更新订单状态
        this.updateOrderStatus(orderSn,OrderConstant.OrderStateEnum.TO_SEND_GOODS.getCode());
        // TODO
        // 2.更新库存信息 库存数量递减

        // 3.购物车中的已经支付的商品移除

        // 4.更新会员积分 ....
    }

前端核心请求跳转

html 复制代码
   <form action="/orderPay/returnUrl" method="get">
              <input type="hidden" name="orderSn" th:value="${orderResponseVO.orderEntity.orderSn}">
              <li>
                <input type="submit" value="立即支付">

              </li>
            </form>


		  <li>
            <img src="/static/order/pay/img\zhifubao.png" style="weight:auto;height:30px;" alt="">
            <a th:href="'/payOrder?orderSn='+${orderResponseVO.orderEntity.orderSn}">
              支付宝
            </a>

          </li>

支付宝支付完成之后的回调请求需要放过拦截器,否则会报错需要重新登录的,因为是不同的一个域名跳转,所以之前保存的用户登录session会话就不会带过来,所以需要放过这个请求接口

new AntPathMatcher().match("/orderPay/**", requestURI)

java 复制代码
public class AuthInterceptor implements HandlerInterceptor {

    public static ThreadLocal threadLocal = new ThreadLocal();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 支付宝的回调我们放过
        String requestURI = request.getRequestURI();

        boolean match = new AntPathMatcher().match("/orderPay/**", requestURI);
        if(match){
            return true;
        }
        // 通过HttpSession获取当前登录的用户信息
        HttpSession session = request.getSession();
        Object attribute = session.getAttribute(AuthConstant.AUTH_SESSION_REDIS);
        if(attribute != null){
            MemberVO memberVO = (MemberVO) attribute;
            threadLocal.set(memberVO);
            return true;
        }
        // 如果 attribute == null 说明没有登录,那么我们就需要重定向到登录页面
        session.setAttribute(AuthConstant.AUTH_SESSION_MSG,"请先登录");
        response.sendRedirect("http://auth.msb.com/login.html");
        return false;
    }
}
相关推荐
工业甲酰苯胺3 小时前
分布式系统架构:服务容错
数据库·架构
Java程序之猿5 小时前
微服务分布式(一、项目初始化)
分布式·微服务·架构
Yvemil77 小时前
《开启微服务之旅:Spring Boot Web开发举例》(一)
前端·spring boot·微服务
小蜗牛慢慢爬行7 小时前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
思忖小下9 小时前
梳理你的思路(从OOP到架构设计)_简介设计模式
设计模式·架构·eit
王ASC10 小时前
SpringMVC的URL组成,以及URI中对/斜杠的处理,解决IllegalStateException: Ambiguous mapping
java·mvc·springboot·web
撒呼呼10 小时前
# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)
数据库·spring boot·spring·mvc·springboot
Yvemil711 小时前
《开启微服务之旅:Spring Boot Web开发》(二)
前端·spring boot·微服务
维李设论11 小时前
Node.js的Web服务在Nacos中的实践
前端·spring cloud·微服务·eureka·nacos·node.js·express