目录

一、创建订单微服务

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());
        //9.减库存

        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;
        }
    }

十、项目结构

项目中用到的一些工具类,会在下一篇做具体介绍

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐