1. 程式人生 > >樂優商城(三十四)——訂單微服務

樂優商城(三十四)——訂單微服務

目錄

一、建立訂單微服務

1.1 建立module

1.2 pom依賴

1.3 配置檔案

1.4 啟動類

1.5 配置匯入

1.6 屬性讀取

1.7 支付工具類

1.8 修改閘道器配置

二、實體類準備

2.1 Order.java

2.2 OrderDetail.java

2.3 OrderStatus.java

2.4 關係

三、Mapper

四、建立訂單

4.1 Controller

4.1.1 分析

4.1.2 程式碼

4.2 Service

4.2.1 介面

4.2.2 實現

五、訂單查詢

5.1 Controller

5.1.1 分析

5.1.2 程式碼

5.2 Service

5.2.1 介面

5.2.2 實現

六、分頁查詢使用者訂單

6.1 Controller

6.1.1 分析

6.1.2 程式碼

6.2 Service

6.2.1 介面

6.2.2 實現

七、更新訂單狀態

7.1 Controller

7.1.1 分析

7.1.2 程式碼

7.2 Service

7.2.1 介面

7.2.2 實現

八、生成微信支付連結

8.1 Controller

8.1.1 分析

8.1.2 程式碼

8.2 Component

九、查詢付款狀態

9.1 Controller

9.1.1 分析

9.1.2 程式碼

9.2 Component

十、專案結構


一、建立訂單微服務

1.1 建立module

1.2 pom依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.order</groupId>
    <artifactId>leyou-order</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mybatis啟動器 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!-- 通用Mapper啟動器 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
        </dependency>
        <!-- mysql驅動 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.leyou.item.interface</groupId>
            <artifactId>leyou-item-interface</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>leyou-common</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.leyou.authentication</groupId>
            <artifactId>leyou-authentication</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
    </dependencies>

</project>

1.3 配置檔案

server:
  port: 8089
spring:
  application:
    name: order-service
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/leyou?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: 123456
    druid:
      initial-size: 5
      min-idle: 5
      max-active: 20
      max-wait: 1000
      test-on-borrow: true
  rabbitmq:
    host: 192.168.19.121
    username: /leyou
    password: leyou
    virtual-host: /leyou
    template:
      retry:
        enabled: true
        initial-interval: 10000ms
        max-interval: 300000ms
        multiplier: 2
      exchange: leyou.item.exchange
    publisher-confirms: true
  redis:
    host: 192.168.19.121
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
    instance-id: ${eureka.instance.ip-address}.${server.port}
    lease-renewal-interval-in-seconds: 3
    lease-expiration-duration-in-seconds: 10

mybatis:
  type-aliases-package: com.leyou.item.pojo
  mapper-locations: mapper/OrderMapper.xml
  configuration:
    map-underscore-to-camel-case: true
mapper:
  not-empty: false
  identity: mysql
leyou:
  worker:
    workerId: 1
    datacenterId: 1
  jwt:
    cookieName: LY_TOKEN
    pubKeyPath: G:\\tmp\\rsa\\rsa.pub # 公鑰地址
  pay:
    appId: 
    mchId: 
    key: 
    connectTimeoutMs: 5000
    readTimeoutMs: 10000

1.4 啟動類

package com.leyou.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author: 98050
 * @Time: 2018-10-27 11:36
 * @Feature: 訂單服務啟動器
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyOrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(LyOrderApplication.class,args);
    }
}

1.5 配置匯入

訂單號生成器,攔截器配置,支付配置,swagger配置,下載

1.6 屬性讀取

讀取配置檔案中的相關屬性,下載

1.7 支付工具類

下載

1.8 修改閘道器配置

修改leyou-api-gateway中的配置

二、實體類準備

2.1 Order.java

package com.leyou.order.pojo;

import org.springframework.data.annotation.Id;

import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;


import java.util.Date;
import java.util.List;

/**
 * @Author: 98050
 * @Time: 2018-10-27 16:33
 * @Feature: 訂單類實體
 */
@Table(name = "tb_order")
public class Order {

    @Id
    private Long orderId;

    /**
     * 總金額
     */
    @NotNull
    private Long totalPay;
    /**
     * 實付金額
     */
    @NotNull
    private Long actualPay;

    /**
     * 支付型別,1、線上支付,2、貨到付款
     */
    @NotNull
    private Integer paymentType;

    /**
     * 參與促銷活動的id
     */
    private String promotionIds;

    /**
     * 郵費
     */
    private String postFee;

    /**
     * 建立時間
     */
    private Date createTime;

    /**
     * 物流名稱
     */
    private String shippingName;

    /**
     * 物流單號
     */
    private String shippingCode;

    /**
     * 使用者id
     */
    private Long userId;

    /**
     * 買家留言
     */
    private String buyerMessage;

    /**
     * 買家暱稱
     */
    private String buyerNick;

    /**
     * 買家是否已經評價
     */
    private Boolean buyerRate;

    /**
     * 收貨人全名
     */
    private String receiver;

    /**
     * 行動電話
     */
    private String receiverMobile;

    /**
     * 省份
     */
    private String receiverState;
    
    /**
     * 城市
     */
    private String receiverCity;
    
    /**
     *  區/縣
     */
    private String receiverDistrict;
    
    /**
     * 收貨地址,如:xx路xx號
     */
    private String receiverAddress;
    
    /**
     * 郵政編碼,如:310001
     */
    private String receiverZip;
    
    /**
     * 發票型別,0無發票,1普通發票,2電子發票,3增值稅發票
     */
    private Integer invoiceType;
    
    /**
     * 訂單來源 1:app端,2:pc端,3:M端,4:微信端,5:手機qq端
     */
    private Integer sourceType;

    @Transient
    private List<OrderDetail> orderDetails;

    @Transient
    private Integer status;

    //省略get和set
}

2.2 OrderDetail.java

package com.leyou.order.pojo;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @Author: 98050
 * @Time: 2018-10-27 16:34
 * @Feature: 訂單詳情資訊實體類
 */
@Table(name = "tb_order_detail")
public class OrderDetail {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /**
     * 訂單id
     */
    private Long orderId;

    /**
     * 商品id
     */
    private Long skuId;

    /**
     * 商品購買數量
     */
    private Integer num;

    /**
     * 商品標題
     */
    private String title;

    /**
     * 商品單價
     */
    private Long price;

    /**
     * 商品規格資料
     */
    private String ownSpec;

    /**
     * 圖片
     */
    private String image;

    //省略get和set
}

2.3 OrderStatus.java

訂單狀態:

  •      初始階段:1、未付款、未發貨;初始化所有資料
  •      付款階段:2、已付款、未發貨;更改付款時間
  •      發貨階段:3、已發貨,未確認;更改發貨時間、物流名稱、物流單號
  •      成功階段:4、已確認,未評價;更改交易結束時間
  •      關閉階段:5、關閉; 更改更新時間,交易關閉時間。
  •      評價階段:6、已評價

package com.leyou.order.pojo;



import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;

/**
 * @Author: 98050
 * @Time: 2018-10-27 16:34
 * @Feature: 訂單狀態實體類
 */
@Table(name = "tb_order_status")
public class OrderStatus {

    /**
     * 初始階段:1、未付款、未發貨;初始化所有資料
     * 付款階段:2、已付款、未發貨;更改付款時間
     * 發貨階段:3、已發貨,未確認;更改發貨時間、物流名稱、物流單號
     * 成功階段:4、已確認,未評價;更改交易結束時間
     * 關閉階段:5、關閉; 更改更新時間,交易關閉時間。
     * 評價階段:6、已評價
     */
    
    @Id
    private Long orderId;
    
    private Integer status;

    /**
     * 建立時間
     */
    private Date createTime;

    /**
     * 付款時間
     */
    private Date paymentTime;

    /**
     *  發貨時間
     */
    private Date consignTime;

    /**
     * 交易結束時間
     */
    private Date endTime;

    /**
     * 交易關閉時間
     */
    private Date closeTime;

    /**
     * 評價時間
     */
    private Date commentTime;

    //省略get和set
}

2.4 關係

一個訂單對應好幾種狀態,通過tb_order_status來記錄訂單所處的不同狀態;一個訂單有好多訂單項,即多個商品資訊,這個用tb_order_detail來記錄。

三、Mapper

所需的通用mapper

package com.leyou.order.mapper;

import tk.mybatis.mapper.common.Mapper;

/**
 * @Author: 98050
 * @Time: 2018-10-27 16:31
 * @Feature:
 */
public interface OrderMapper extends Mapper {
}
package com.leyou.order.mapper;

import com.leyou.order.pojo.OrderDetail;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.special.InsertListMapper;

/**
 * @Author: 98050
 * @Time: 2018-10-27 16:33
 * @Feature:
 */
public interface OrderDetailMapper extends Mapper<OrderDetail>, InsertListMapper<OrderDetail> {
}
package com.leyou.order.mapper;

import com.leyou.order.pojo.OrderStatus;
import tk.mybatis.mapper.common.Mapper;

/**
 * @Author: 98050
 * @Time: 2018-10-27 16:31
 * @Feature:
 */
public interface OrderStatusMapper extends Mapper<OrderStatus> {
}

在啟動類中新增mapper掃描:

四、建立訂單

4.1 Controller

4.1.1 分析

  • 請求方式:POST

  • 請求路徑:api.leyou.com/api/order

  • 請求引數:order物件

  • 返回結果:建立好的訂單id

4.1.2 程式碼

    /**
     * 建立訂單
     * @param order 訂單物件
     * @return 訂單編號
     */
    @PostMapping
    public ResponseEntity<Long> createOrder(@RequestBody @Valid Order order){
        Long id = this.orderService.createOrder(order);
        return new ResponseEntity<>(id, HttpStatus.CREATED);
    }

4.2 Service

4.2.1 介面

4.2.2 實現

邏輯:

  • 生成訂單id
  • 獲取登入使用者的資訊
  • 初始化訂單資料:買家暱稱、是否評論、建立時間、訂單號、使用者id
  • 儲存訂單資料
  • 初始化訂單狀態資料:訂單id、訂單建立時間、訂單狀態(初始狀態:1,未付款)
  • 儲存訂單狀態資料
  • 為訂單詳情中的資料新增訂單號,因為一個訂單下有多個訂單項
  • 儲存訂單詳情資料
package com.leyou.order.service.impl;

import com.leyou.auth.entity.UserInfo;
import com.leyou.order.interceptor.LoginInterceptor;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.OrderStatusMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderStatus;
import com.leyou.order.service.OrderService;
import com.leyou.utils.IdWorker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * @Author: 98050
 * @Time: 2018-10-27 16:37
 * @Feature:
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderStatusMapper orderStatusMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long createOrder(Order order) {
        //1.生成orderId
        long orderId = idWorker.nextId();
        //2.獲取登入的使用者
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        //3.初始化資料
        order.setBuyerNick(userInfo.getUsername());
        order.setBuyerRate(false);
        order.setCreateTime(new Date());
        order.setOrderId(orderId);
        order.setUserId(userInfo.getId());
        //4.儲存資料
        this.orderMapper.insertSelective(order);

        //5.儲存訂單狀態
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setOrderId(orderId);
        orderStatus.setCreateTime(order.getCreateTime());
        //初始狀態未未付款:1
        orderStatus.setStatus(1);
        //6.儲存資料
        this.orderStatusMapper.insertSelective(orderStatus);

        //7.在訂單詳情中新增orderId
        order.getOrderDetails().forEach(orderDetail -> orderDetail.setOrderId(orderId));
        //8.儲存訂單詳情,使用批量插入功能
        this.orderDetailMapper.insertList(order.getOrderDetails());

        logger.debug("生成訂單,訂單編號:{},使用者id:{}", orderId, userInfo.getId());
        return orderId;
    }
}

五、訂單查詢

5.1 Controller

5.1.1 分析

  • 請求方式:GET

  • 請求路徑:api.leyou.com/api/order/id

  • 請求引數:訂單編號

  • 返回結果:訂單物件

5.1.2 程式碼

    /**
     * 查詢訂單
     * @param id 訂單編號
     * @return 訂單物件
     */
    @GetMapping("{id}")
    public ResponseEntity<Order> queryOrderById(@PathVariable("id") Long id){
        Order order = this.orderService.queryOrderById(id);
        if (order == null){
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
        return ResponseEntity.ok(order);
    }

5.2 Service

5.2.1 介面

5.2.2 實現

邏輯:

  • 根據訂單號查詢訂單物件
  • 查詢訂單詳情,自定義查詢規則(orderId = 訂單號)。
  • 查詢訂單狀態
  • 給已經查詢到的訂單物件填充訂單詳情
  • 給已經查詢到的訂單物件設定訂單狀態
    /**
     * 根據訂單號查詢訂單
     * @param id
     * @return
     */
    @Override
    public Order queryOrderById(Long id) {
        //1.查詢訂單
        Order order = this.orderMapper.selectByPrimaryKey(id);
        //2.查詢訂單詳情
        Example example = new Example(OrderDetail.class);
        example.createCriteria().andEqualTo("orderId",id);
        List<OrderDetail> orderDetail = this.orderDetailMapper.selectByExample(example);
        //3.查詢訂單狀態
        OrderStatus orderStatus = this.orderStatusMapper.selectByPrimaryKey(order.getOrderId());
        //4.order物件填充訂單詳情
        order.setOrderDetails(orderDetail);
        //5.order物件設定訂單狀態
        order.setStatus(orderStatus.getStatus());
        //6.返回order
        return order;
    }

六、分頁查詢使用者訂單

6.1 Controller

6.1.1 分析

  • 請求方式:GET

  • 請求路徑:api.leyou.com/api/order/list

  • 請求引數:page(頁數)、rows(每頁大小)、status(頁面狀態)

  • 返回結果:分頁物件

6.1.2 程式碼

    /**
     * 分頁查詢當前已經登入的使用者訂單
     * @param page 頁數
     * @param rows 每頁大小
     * @param status 訂單狀態
     * @return
     */
    @GetMapping("list")
    public ResponseEntity<PageResult<Order>> queryUserOrderList(
            @RequestParam(value = "page",defaultValue = "1")Integer page,
            @RequestParam(value = "rows",defaultValue = "5")Integer rows,
            @RequestParam(value = "status",required = false)Integer status
    ){

        PageResult<Order> result = this.orderService.queryUserOrderList(page,rows,status);
        if (result == null){
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(result);
    }

6.2 Service

6.2.1 介面

6.2.2 實現

需求:

訂單的分頁查詢還需要根據訂單狀態來篩選,因為後期要分別進行展示,而訂單狀態是在單獨一個表中,要進行分頁查詢的話,只能是tb_order表和tb_order_status兩個表先進行連線,然後對其進行分頁查詢,查詢完畢後再填充訂單詳情。這裡用mybatis的xml配置檔案方式來進行查詢

在resources中建立mapper資料夾

建立OrderMapper.xml資料庫對映檔案

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.leyou.order.mapper.OrderMapper">
    <resultMap id="OrderWithDetail" type="com.leyou.order.pojo.Order" autoMapping="true">
        <id column="order_id" property="orderId"></id>
    </resultMap>
    <select id="queryOrderList" resultMap="OrderWithDetail">
        SELECT o.order_id,o.actual_pay, o.total_pay,o.create_time, os.status
        FROM tb_order o
        LEFT JOIN tb_order_status os ON os.order_id = o.order_id
        WHERE o.user_id = #{userId}
        <if test="status != null and status != 0">
            AND os.status = #{status}
        </if>
        ORDER BY o.create_time DESC
    </select>
</mapper>

在mapper中定義方法

package com.leyou.order.mapper;

import com.leyou.order.pojo.Order;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;

import java.util.List;


/**
 * @Author: 98050
 * @Time: 2018-10-27 16:31
 * @Feature:
 */
public interface OrderMapper extends Mapper<Order> {
    /**
     * 分頁查詢訂單
     * @param userId
     * @param status
     * @return
     */
    List<Order> queryOrderList(@Param("userId") Long userId, @Param("status") Integer status);
}

邏輯:

  • 分頁
  • 獲取登入使用者
  • 查詢
  • 訂單詳情填充
  • 返回

程式碼

    /**
     * 查詢當前登入使用者的訂單,通過訂單狀態進行篩選
     * @param page
     * @param rows
     * @param status
     * @return
     */
    @Override
    public PageResult<Order> queryUserOrderList(Integer page, Integer rows, Integer status) {
        try{
            //1.分頁
            PageHelper.startPage(page,rows);
            //2.獲取登入使用者
            UserInfo userInfo = LoginInterceptor.getLoginUser();
            //3.查詢
            Page<Order> pageInfo = (Page<Order>) this.orderMapper.queryOrderList(userInfo.getId(), status);
            //4.填充orderDetail
            List<Order> orderList = pageInfo.getResult();
            orderList.forEach(order -> {
                Example example = new Example(OrderDetail.class);
                example.createCriteria().andEqualTo("orderId",order.getOrderId());
                List<OrderDetail> orderDetailList = this.orderDetailMapper.selectByExample(example);
                order.setOrderDetails(orderDetailList);
            });
            return new PageResult<>(pageInfo.getTotal(),(long)pageInfo.getPages(), orderList);
        }catch (Exception e){
            logger.error("查詢訂單出錯",e);
            return null;
        }
    }

七、更新訂單狀態

7.1 Controller

7.1.1 分析

  • 請求方式:PUT

  • 請求路徑:api.leyou.com/api/order/id/status

  • 請求引數:id(訂單編號)、status(訂單狀態)

  • 返回結果:true或false

7.1.2 程式碼

    /**
     * 更新訂單狀態
     * @param id
     * @param status
     * @return
     */
    @PutMapping("{id}/{status}")
    public ResponseEntity<Boolean> updateOrderStatus(@PathVariable("id") Long id,@PathVariable("status") Integer status){
        Boolean result = this.orderService.updateOrderStatus(id,status);
        if (result == null){
            //返回400
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }
        //返回204
        return new ResponseEntity<>(result,HttpStatus.NO_CONTENT);
    }

7.2 Service

7.2.1 介面

7.2.2 實現

邏輯:

  • 根據使用者id和訂單狀態構造orderStatus物件
  • 根據出入的status判斷是哪一個狀態,然後修改對應的時間
  • 然後返回更新結果
 /**
     * 更新訂單狀態
     * @param id
     * @param status
     * @return
     */
    @Override
    public Boolean updateOrderStatus(Long id, Integer status) {
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setOrderId(id);
        orderStatus.setStatus(status);
        //1.根據狀態判斷要修改的時間
        switch (status){
            case 2:
                //2.付款時間
                orderStatus.setPaymentTime(new Date());
                break;
            case 3:
                //3.發貨時間
                orderStatus.setConsignTime(new Date());
                break;
            case 4:
                //4.確認收貨,訂單結束
                orderStatus.setEndTime(new Date());
                break;
            case 5:
                //5.交易失敗,訂單關閉
                orderStatus.setCloseTime(new Date());
                break;
            case 6:
                //6.評價時間
                orderStatus.setCommentTime(new Date());
                break;

                default:
                    return null;
        }
        int count = this.orderStatusMapper.updateByPrimaryKeySelective(orderStatus);
        return count == 1;
    }

八、生成微信支付連結

8.1 Controller

8.1.1 分析

  • 請求方式:GET

  • 請求路徑:api.leyou.com/api/order/url/id

  • 請求引數:id(訂單編號)

  • 返回結果:支付連結

8.1.2 程式碼

    /**
     * 根據訂單id生成付款連結
     * @param orderId
     * @return
     */
    @GetMapping("url/{id}")
    public ResponseEntity<String> generateUrl(@PathVariable("id") Long orderId){
        String url = this.payHelper.createPayUrl(orderId);
        if (StringUtils.isNotBlank(url)){
            return ResponseEntity.ok(url);
        }else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
    }

8.2 Component

    public String createPayUrl(Long orderId) {
        String key = "leyou.pay.url." + orderId;
        try {
            String url = this.redisTemplate.opsForValue().get(key);
            if (StringUtils.isNotBlank(url)) {
                return url;
            }
        } catch (Exception e) {
            logger.error("查詢快取付款連結異常,訂單編號:{}", orderId, e);
        }

        try {
            Map<String, String> data = new HashMap<>();
            // 商品描述
            data.put("body", "樂優商城測試");
            // 訂單號
            data.put("out_trade_no", orderId.toString());
            //貨幣
            data.put("fee_type", "CNY");
            //金額,單位是分
            data.put("total_fee", "1");
            //呼叫微信支付的終端IP(estore商城的IP)
            data.put("spbill_create_ip", "127.0.0.1");
            //回撥地址
            data.put("notify_url", "http://test.leyou.com/wxpay/notify");
            // 交易型別為掃碼支付
            data.put("trade_type", "NATIVE");
            //商品id,使用假資料
            data.put("product_id", "1234567");

            Map<String, String> result = this.wxPay.unifiedOrder(data);

            if ("SUCCESS".equals(result.get("return_code"))) {
                String url = result.get("code_url");
                // 將付款地址快取,時間為10分鐘
                try {
                    this.redisTemplate.opsForValue().set(key, url, 10, TimeUnit.MINUTES);
                } catch (Exception e) {
                    logger.error("快取付款連結異常,訂單編號:{}", orderId, e);
                }
                return url;
            } else {
                logger.error("建立預交易訂單失敗,錯誤資訊:{}", result.get("return_msg"));
                return null;
            }
        } catch (Exception e) {
            logger.error("建立預交易訂單異常", e);
            return null;
        }
    }

九、查詢付款狀態

9.1 Controller

9.1.1 分析

  • 請求方式:GET

  • 請求路徑:api.leyou.com/api/order/state/id

  • 請求引數:id(訂單編號)

  • 返回結果:支付狀態(未支付:0;支付成功:1;支付失敗:2)

9.1.2 程式碼

    /**
     * 查詢付款狀態
     * @param orderId
     * @return
     */
    @GetMapping("state/{id}")
    public ResponseEntity<Integer> queryPayState(@PathVariable("id") Long orderId){
        PayState payState = this.payHelper.queryOrder(orderId);
        return ResponseEntity.ok(payState.getValue());
    }

9.2 Component

    /**
     * 查詢訂單狀態
     *
     * @param orderId
     * @return
     */
    public PayState queryOrder(Long orderId) {
        Map<String, String> data = new HashMap<>();
        // 訂單號
        data.put("out_trade_no", orderId.toString());
        try {
            Map<String, String> result = this.wxPay.orderQuery(data);
            if (result == null) {
                // 未查詢到結果,認為是未付款
                return PayState.NOT_PAY;
            }
            String state = result.get("trade_state");
            if ("SUCCESS".equals(state)) {
                // success,則認為付款成功

                // 修改訂單狀態
                this.orderService.updateOrderStatus(orderId, 2);
                return PayState.SUCCESS;
            } else if (StringUtils.equals("USERPAYING", state) || StringUtils.equals("NOTPAY", state)) {
                // 未付款或正在付款,都認為是未付款
                return PayState.NOT_PAY;
            } else {
                // 其它狀態認為是付款失敗
                return PayState.FAIL;
            }
        } catch (Exception e) {
            logger.error("查詢訂單狀態異常", e);
            return PayState.NOT_PAY;
        }
    }

十、專案結構

專案中用到的一些工具類,會在下一篇做具體介紹