在前面我们业务功能篇98-99中,我们介绍了电商项目中的订单模块服务,那么最后就是需要进行支付动作,那么我们这里就通过订阅第三方平台支付宝的支付调用接口功能,来进一步完成订单提交后的支付动作,支付宝的接口使用可以登录官网开发指南详情去了解
在我们对应需要进行支付调用的订单服务中的pom文件加入依赖,其他服务不涉及的不需要加
-
- <dependency>
- <groupId>com.alipay.sdkgroupId>
- <artifactId>alipay-sdk-javaartifactId>
- <version>4.31.12.ALLversion>
- dependency>
- 根据支付宝的接口使用方式,传递对应订单封装类对象,进行支付操作,并且还有同步回调地址,在支付完成之后自动跳转到我们指定页面
- 回调地址:public static String return_url = "http://order.msb.com/orderPay/returnUrl"; 指定到该接口,该接口会进行支付完成后需要的操作,比如修改订单的状态为已完成,发货状态为待发货等等.. 然后return指定的html订单详情页面list.html
-
-
- /**
- * 支付宝的配置文件
- */
- //@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;
- }
- }
payOrder:在订单页面中,点击 支付宝发起支付请求的方法orderPay:支付完成之后,会同步回调到订单详情的方法,同时执行支付完成后需要的动作,比如修改订单状态为 关闭, 发货状态为待发货等等..
- @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";
- }
- @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.更新会员积分 ....
- }
- <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)
- 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;
- }
- }