Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)二十二(下单和微信支付)
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)二十(下单)0.学习目标会调用订单系统接口实现订单结算功能实现微信支付功能1.订单系统接口1.1.创建订单微服务1.1.1创建model1.1.2 在pom.xml引入依赖<?xml version="1.0" encoding="UTF-8"?><project xmln
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)二十(下单)
0.学习目标
- 会调用订单系统接口
- 实现订单结算功能
- 实现微信支付功能
1.订单系统接口
1.1.创建订单微服务
1.1.1创建model
1.1.2 在pom.xml引入依赖
<?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.service</groupId>
<artifactId>ly-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.service</groupId>
<artifactId>ly-item-interface</artifactId>
<version>${leyou.latest.version}</version>
</dependency>
<dependency>
<groupId>com.leyou.common</groupId>
<artifactId>ly-common</artifactId>
<version>${leyou.latest.version}</version>
</dependency>
<dependency>
<groupId>com.leyou.auth</groupId>
<artifactId>ly-auth-common</artifactId>
<version>${leyou.latest.version}</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>
<version>0.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
</dependencies>
</project>
1.1.3 创建配置文件
server:
port: 8071
spring:
application:
name: order-service
datasource:
url: jdbc:mysql://127.0.0.1:3306/yun6
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
jackson:
default-property-inclusion: non_null
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
registry-fetch-interval-seconds: 5
instance:
ip-address: 127.0.0.1
prefer-ip-address: true
mybatis:
type-aliases-package: com.leyou.order.pojo
创建上述对应的别名包
1.1.4 创建启动类
package com.leyou;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("com.leyou.order.mapper")
public class LyOrderApplication {
public static void main(String[] args) {
SpringApplication.run(LyOrderApplication.class,args);
}
}
1.1.5 配置网关
order-service: /order/**
1.1.6 公钥配置
ly:
jwt:
pubKeyPath: C:\\Users\\ZHENG\\Desktop\\leyou_msgrs\\rsa\\rsa.pub # 公钥地址
cookieName: LY_TOKEN # cookie的名称
1.1.7 判断登录用户拦截器相关配置
package com.leyou.order.config;
import com.leyou.auth.utils.RsaUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.annotation.PostConstruct;
import java.security.PublicKey;
@Data
@ConfigurationProperties(prefix = "ly.jwt")
@Slf4j
public class JwtProperties {
private String pubKeyPath;// 公钥
private PublicKey publicKey; // 公钥
private String cookieName;
@PostConstruct
public void init(){
try {
// 获取公钥和私钥
this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
} catch (Exception e) {
log.error("初始化公钥失败!", e);
throw new RuntimeException();
}
}
}
package com.leyou.order.interceptors;
import com.leyou.auth.entity.UserInfo;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.common.utils.CookieUtils;
import com.leyou.order.config.JwtProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class UserInterceptor implements HandlerInterceptor {
private JwtProperties prop;
private static final ThreadLocal<UserInfo> tl = new ThreadLocal<>();
public UserInterceptor(JwtProperties prop) {
this.prop = prop;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
//获取Cookie
String token = CookieUtils.getCookieValue(request, prop.getCookieName());
try {
//解析token
UserInfo user = JwtUtils.getUserInfo(prop.getPublicKey(), token);
//传递User
tl.set(user);
//放行
return true;
} catch (Exception e) {
log.error("[购物车服务]解析用户身份失败", e);
return false;
}
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex)
throws Exception {
tl.remove();
}
public static UserInfo getLoginUser() {
return tl.get();
}
}
package com.leyou.order.config;
import com.leyou.order.interceptors.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class MvcConfig implements WebMvcConfigurer {
@Autowired
private JwtProperties prop;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserInterceptor(prop)).addPathPatterns("/**");
}
}
1.2.数据库设计
DROP TABLE IF EXISTS `tb_order`;
CREATE TABLE `tb_order` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`total_pay` bigint(20) NOT NULL COMMENT '总金额,单位为分',
`actual_pay` bigint(20) NOT NULL COMMENT '实付金额。单位:分。如:20007,表示:200元7分',
`promotion_ids` varchar(256) COLLATE utf8_bin DEFAULT '',
`payment_type` tinyint(1) unsigned zerofill NOT NULL COMMENT '支付类型,1、在线支付,2、货到付款',
`post_fee` bigint(20) NOT NULL COMMENT '邮费。单位:分。如:20007,表示:200元7分',
`create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
`shipping_name` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流名称',
`shipping_code` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流单号',
`user_id` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '用户id',
`buyer_message` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '买家留言',
`buyer_nick` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '买家昵称',
`buyer_rate` tinyint(1) DEFAULT NULL COMMENT '买家是否已经评价,0未评价,1已评价',
`receiver_state` varchar(128) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(省)',
`receiver_city` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(市)',
`receiver_district` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(区/县)',
`receiver_address` varchar(256) COLLATE utf8_bin DEFAULT '' COMMENT '收获地址(街道、住址等详细地址)',
`receiver_mobile` varchar(11) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人手机',
`receiver_zip` varchar(16) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人邮编',
`receiver` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人',
`invoice_type` int(1) DEFAULT '0' COMMENT '发票类型(0无发票1普通发票,2电子发票,3增值税发票)',
`source_type` int(1) DEFAULT '2' COMMENT '订单来源:1:app端,2:pc端,3:M端,4:微信端,5:手机qq端',
PRIMARY KEY (`order_id`) USING BTREE,
KEY `create_time` (`create_time`) USING BTREE,
KEY `buyer_nick` (`buyer_nick`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;
DROP TABLE IF EXISTS `tb_order_detail`;
CREATE TABLE `tb_order_detail` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单详情id ',
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`sku_id` bigint(20) NOT NULL COMMENT 'sku商品id',
`num` int(11) NOT NULL COMMENT '购买数量',
`title` varchar(256) NOT NULL COMMENT '商品标题',
`own_spec` varchar(1024) DEFAULT '' COMMENT '商品动态属性键值集',
`price` bigint(20) NOT NULL COMMENT '价格,单位:分',
`image` varchar(128) DEFAULT '' COMMENT '商品图片',
PRIMARY KEY (`id`) USING BTREE,
KEY `key_order_id` (`order_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=126 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='订单详情表';
DROP TABLE IF EXISTS `tb_order_status`;
CREATE TABLE `tb_order_status` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`status` int(1) DEFAULT NULL COMMENT '状态:1、未付款 2、已付款,未发货 3、已发货,未确认 4、交易成功 5、交易关闭 6、已评价',
`create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
`payment_time` datetime DEFAULT NULL COMMENT '付款时间',
`consign_time` datetime DEFAULT NULL COMMENT '发货时间',
`end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
`close_time` datetime DEFAULT NULL COMMENT '交易关闭时间',
`comment_time` datetime DEFAULT NULL COMMENT '评价时间',
PRIMARY KEY (`order_id`) USING BTREE,
KEY `status` (`status`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='订单状态表';
1.3.相关实体类
package com.leyou.order.pojo;
import lombok.Data;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.util.Date;
import java.util.List;
@Data
@Table(name = "tb_order")
public class Order {
@Id
private Long orderId;// id
private Long totalPay;// 总金额
private Long actualPay;// 实付金额
private Integer paymentType; // 支付类型,1、在线支付,2、货到付款
private String promotionIds; // 参与促销活动的id
private Long postFee = 0L;// 邮费
private Date createTime;// 创建时间
private String shippingName;// 物流名称
private String shippingCode;// 物流单号
private Long userId;// 用户id
private String buyerMessage;// 买家留言
private String buyerNick;// 买家昵称
private Boolean buyerRate;// 买家是否已经评价
private String receiver; // 收货人全名
private String receiverMobile; // 移动电话
private String receiverState; // 省份
private String receiverCity; // 城市
private String receiverDistrict; // 区/县
private String receiverAddress; // 收货地址,如:xx路xx号
private String receiverZip; // 邮政编码,如:310001
private Integer invoiceType = 0;// 发票类型,0无发票,1普通发票,2电子发票,3增值税发票
private Integer sourceType = 1;// 订单来源 1:app端,2:pc端,3:M端,4:微信端,5:手机qq端
@Transient
private OrderStatus orderStatus;
@Transient
private List<OrderDetail> orderDetails;
}
package com.leyou.order.pojo;
import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;
import javax.persistence.Id;
import javax.persistence.Table;
@Data
@Table(name = "tb_order_detail")
public class OrderDetail {
@Id
@KeySql(useGeneratedKeys = true)
private Long id;
private Long orderId;// 订单id
private Long skuId;// 商品id
private Integer num;// 商品购买数量
private String title;// 商品标题
private Long price;// 商品单价
private String ownSpec;// 商品规格数据
private String image;// 图片
}
package com.leyou.order.pojo;
import lombok.Data;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@Data
@Table(name = "tb_order_status")
public class OrderStatus {
@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;// 评价时间
}
1.4.相关数据传输对象DTO
package com.leyou.order.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CartDTO {
private Long skuId;//商品skuId
private Integer num;//购买数量
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderDTO {//数据传输对象
@NonNull //@NonNull校验不能为空
private Long addressId;
@NonNull
private Integer paymentType;
@NonNull
private List<CartDTO> carts;
}
1.5.相关Controller
package com.leyou.order.web;
import com.leyou.order.dto.OrderDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("order")
public class OrderController {
/*
创建订单
*/
@PostMapping
public ResponseEntity<Long> createOrder(@RequestBody OrderDTO orderDTO){
return null;
}
}
1.6.相关Service
package com.leyou.order.service;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
}
1.7.相关Mapper
package com.leyou.order.mapper;
import com.leyou.common.mapper.BaseMapper;
import com.leyou.order.pojo.Order;
public interface OrderMapper extends BaseMapper<Order> {
}
package com.leyou.order.mapper;
import com.leyou.common.mapper.BaseMapper;
import com.leyou.order.pojo.OrderDetail;
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
}
package com.leyou.order.mapper;
import com.leyou.common.mapper.BaseMapper;
import com.leyou.order.pojo.OrderStatus;
public interface OrderStatusMapper extends BaseMapper<OrderStatus> {
}
1.8.完善OrderService
package com.leyou.order.service;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.OrderStatusMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderDetailMapper detailMapper;
@Autowired
private OrderStatusMapper statusMapper;
}
1.9.完善OrderController
2.0.实现orderService的createOrder方法
创建订单逻辑比较复杂,需要组装订单数据,基本步骤如下:
- 获取登录用户信息
- 生成订单编号,初始化订单基本信息
- 查询收货人信息
- 查询商品信息
- 封装OrderDetail信息
- 计算总金额、实付金额
- 保存订单状态信息
- 删除购物车中已购买商品减库存
2.0.1生成订单编号(雪花算法)
雪花算法是由Twitter公司开源的snowflake(雪花)算法。
- 雪花算法的原理
雪花算法会生成一个64位的二进制数据,为一个Long型。
(转换成字符串后长度最多19),其基本结构:
第一位:为未使用
第二部分:41位为毫秒级时间(41位的长度可以使用69年)
第三部分:5位datacenterld
和5位workerld
(10位的长度最多支持部署1024个节点)
第四部分:最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
snowflake
生成的ID整体上按照时间自增排序,
并且整个分布式系统内不会产生ID碰撞(由datacenter
和workerld
作区分),
并且效率较高。
经测试snowflake
每秒能够产生26万个ID。
- 配置
ly:
worker:
workerId : 1
dataCenterId : 1
- 加载属性
package com.leyou.order.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "ly.worker")
public class IdWorkerProperties {
private long workerId;
private long dataCenterId;
}
- 编写配置类
package com.leyou.order.config;
import com.leyou.common.utils.IdWorker;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(IdWorkerProperties.class)
public class IdWorkerConfig {
@Bean
public IdWorker idWorker(IdWorkerProperties prop){
return new IdWorker(prop.getWorkerId(),prop.getDataCenterId());
}
}
2.0.2 准备假物流数据
我们前端页面传来的是addressld,我们需要根据id查询物流信息,
但是因为还没做物流地址管理。
所以我们准备一些假数据。
首先是实体类:
package com.leyou.order.dto;
import lombok.Data;
@Data
public class AddressDTO {
private Long id;
private String name;//收件人姓名
private String phone;//电话
private String state;//省份
private String city;//城市
private String district;//区
private String address;//街道地址
private String zipCode;//邮编
private Boolean isDefault;
}
package com.leyou.order.client;
import com.leyou.order.dto.AddressDTO;
import java.util.ArrayList;
import java.util.List;
public abstract class AddressClient {
public static final List<AddressDTO> addressList = new ArrayList<AddressDTO>() {
{
AddressDTO address = new AddressDTO();
address.setId(1L);
address.setAddress("太阳系");
address.setCity("银河系");
address.setDistrict("火星");
address.setName("大哥");
address.setPhone("15800000000");
address.setState("阿拉比亚大陆(Arabia Terra)");
address.setZipCode("210000" ) ;
address.setIsDefault(true) ;
add(address);
AddressDTO address2 = new AddressDTO();address2.setId(2L);
address.setAddress("太阳系");
address.setCity("银河系");
address2.setDistrict("天王星");
address2.setName("张三");
address2.setPhone("13600000000" );
address2.setState("北京");
address2.setZipCode("100000");
address2.setIsDefault(false);
add(address2);
}
};
public static AddressDTO findById(Long id) {
for (AddressDTO addressDTO : addressList) {
if (addressDTO.getId() == id)
return addressDTO;
}
return null;
}
}
2.0.3 在ly-item的ly-item-interface当中新增通过sku的id集合查询其所有sku的接口
/*
通过sku的id集合查询其所有sku
*/
@GetMapping("sku/list/ids")
List<Sku> querySkuBySpuId(@RequestParam("ids") List<Long> ids);
2.0.4 在Order当中定义对应client使用上述的接口
package com.leyou.order.client;
import com.leyou.item.api.GoodsApi;
import org.springframework.cloud.openfeign.FeignClient;
@FeignClient("item-service")
public interface GoodsClient extends GoodsApi {
}
2.0.5 完善OrderService相关的工具类
2.0.5.1 定义异常枚举
CREATE_ORDER_ERROR(500,"创建订单失败"),
2.0.5.2 定义订单状态枚举
package com.leyou.order.enums;
public enum OrderStatusEnum {
UN_PAY(1,"未付款"),
PAYED(2,"已付款,未发货"),
DELIVERED(3,"已发货,未确认"),
SUCCESS(4,"已确认,未评价"),
CLOSED(5,"已关闭,交易失败"),
RATED(6,"已评价"),
;
private int code;
private String desc;
OrderStatusEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int value(){
return this.code;
}
}
2.0.5.3 在StockMapper当中编写键库存的代码
public interface StockMapper extends BaseMapper<Stock>{
@Update("UPDATE tb_stock SET stock = stock - #{num} WHERE sku_id = #{id} AND stock >= #{num}")
int decreaseStock(@Param("id") Long id, @Param("num") Integer num);
}
这里减库存并没有采用先查询库存,判断充足才减库存的方案,那样会有线程安全问题,当然可以通过加锁解决。不过我们此处为了效率,并没有使用悲观锁,而是对库存采用了乐观锁方案
2.0.5.4 在商品微服务当中定义减库存的内容
- 在ly-common当中创建CartDTO,将下面order当中CartDTO复制一份到ly-common当中
- GoodsController当中创建decreaseStock方法
/*
减库存
*/
@PostMapping("stock/decrease")
public ResponseEntity<Void> decreaseStock(@RequestBody List<CartDTO> carts){
goodsService.decreaseStock(carts);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
- GoodsService
@Transactional
public void decreaseStock(List<CartDTO> carts) {
for (CartDTO cart : carts) {
//键库存
int count = stockMapper.decreaseStock(cart.getSkuId(), cart.getNum());
if(count != 1){
throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH);
}
}
}
- 测试
package com.leyou.item.service;
import com.leyou.common.dto.CartDTO;
import com.leyou.item.api.GoodsApi;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class GoodsServiceTest {
@Autowired
private GoodsService goodsService;
@Test
public void decreaseStock(){
List<CartDTO> cartDTOS =
Arrays.asList(
new CartDTO(2600242L, 2),
new CartDTO(2600248L, 2)
);
goodsService.decreaseStock(cartDTOS);
}
}
运行成功
2.0.5.5 将接口提供到API当中
/*
减库存
*/
@PostMapping("stock/decrease")
void decreaseStock(@RequestBody List<CartDTO> carts);
2.0.6 完善OrderService的createOrder方法
package com.leyou.order.service;
import com.leyou.auth.entity.UserInfo;
import com.leyou.common.dto.CartDTO;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.pojo.Sku;
import com.leyou.order.client.AddressClient;
import com.leyou.order.client.GoodsClient;
import com.leyou.order.dto.AddressDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.interceptors.UserInterceptor;
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.OrderDetail;
import com.leyou.order.pojo.OrderStatus;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderDetailMapper detailMapper;
@Autowired
private OrderStatusMapper statusMapper;
@Autowired
private IdWorker idWorker;
@Autowired
private GoodsClient goodsClient;
@Transactional
public Long createOrder(OrderDTO orderDTO) {
//新增订单
Order order = new Order();
//订单编号
long orderId = idWorker.nextId();
order.setOrderId(orderId);
order.setCreateTime(new Date());
order.setPaymentType(orderDTO.getPaymentType());
//用户信息
UserInfo user = UserInterceptor.getLoginUser();
order.setUserId(user.getId());
order.setBuyerNick(user.getUserName());
order.setBuyerRate(false);
//收货人地址信息
//获取收货人信息
AddressDTO addr = AddressClient.findById(orderDTO.getAddressId());
order.setReceiver(addr.getName());
order.setReceiverAddress(addr.getAddress());
order.setReceiverCity(addr.getCity());
order.setReceiverDistrict(addr.getDistrict());
order.setReceiverMobile(addr.getPhone());
order.setReceiverState(addr.getState());
order.setReceiverZip(addr.getZipCode());
//金额相关
//把CartDTO 转为一个map,key是sku的id,值是num
Map<Long, Integer> numMap = orderDTO.getCarts().stream()
.collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
//获取所有的sku的id
Set<Long> ids = numMap.keySet();
//根据id查询sku
List<Sku> skus = goodsClient.querySkuBySpuId(new ArrayList<>(ids));
//准备orderDetail
List<OrderDetail> details = new ArrayList<>();
long totalPay = 0L;
for (Sku sku : skus) {
//计算商品总价
totalPay += sku.getPrice() * numMap.get(sku.getId());
//封装OrderDetail
OrderDetail detail = new OrderDetail();
detail.setImage(StringUtils.substringBefore(sku.getImages(),","));
detail.setNum(numMap.get(sku.getId()));
detail.setOrderId(orderId);
detail.setOwnSpec(sku.getOwnSpec());
detail.setPrice(sku.getPrice());
detail.setSkuId(sku.getId());
detail.setTitle(sku.getTitle());
details.add(detail);
}
//总金额
order.setTotalPay(totalPay);
//实付金额:总金额+邮费-优惠金额
order.setActualPay(totalPay + order.getPostFee() - 0);
//把order写入数据库
int count = orderMapper.insertSelective(order);
if(count != 1){
log.error("[创建订单] 创建订单失败,orderId:{}",orderId);
throw new LyException(ExceptionEnum.CREATE_ORDER_ERROR);
}
//新增订单详情
count = detailMapper.insertList(details);
if(count != details.size()){
log.error("[创建订单状态] 创建订单失败,orderId:{}",orderId);
throw new LyException(ExceptionEnum.CREATE_ORDER_ERROR);
}
//新增订单状态
OrderStatus orderStatus = new OrderStatus();
orderStatus.setCreateTime(order.getCreateTime());
orderStatus.setOrderId(orderId);
orderStatus.setStatus(OrderStatusEnum.UN_PAY.value());
count = statusMapper.insertSelective(orderStatus);
if (count != 1) {
log.error("[创建订单状态] 创建订单失败,orderId:{}",orderId);
throw new LyException(ExceptionEnum.CREATE_ORDER_ERROR);
}
//减库存
List<CartDTO> carts = orderDTO.getCarts();
goodsClient.decreaseStock(carts);
return orderId;
}
}
2.0.7 测试创建订单
2.订单
(1)点击支付后会跳转到支付页面
(2)实现上述所对应的接口(先实现查询订单)
(a)OrderController当中queryOrderById方法
@GetMapping("{id}")
public ResponseEntity<Order> queryOrderById(@PathVariable("id") Long id){
return ResponseEntity.ok(orderService.queryOrderById(id));
}
(b)完善OrderService当中对应的方法
ORDER_NOT_FOUND(404,"订单不存在"),
ORDER_DETAIL_NOT_FOUND(404,"订单详情不存在"),
ORDER_STATUS_NOT_FOUND(404,"订单状态不存在"),
public Order queryOrderById(Long id) {
//查询订单
Order order = orderMapper.selectByPrimaryKey(id);
if(order == null){
//订单不存在
throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
}
//查询订单详情
OrderDetail detail = new OrderDetail();
detail.setOrderId(id);
List<OrderDetail> details = detailMapper.select(detail);
if(CollectionUtils.isEmpty(details)){
throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
}
order.setOrderDetails(details);
//查询订单状态
OrderStatus orderStatus = statusMapper.selectByPrimaryKey(id);
if(orderStatus == null){
throw new LyException(ExceptionEnum.ORDER_STATUS_NOT_FOUND);
}
order.setOrderStatus(orderStatus);
return order;
}
重新运行并测试
刷新支付页面
成功显示对应的数据
3.微信支付
(1)官网:
https://pay.weixin.qq.com/index.php
填写信息
(2)开发流程(实现后台代码)
模式二与模式一相比,流程更为简单,不依赖设置的回调支付URL。
商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url;
商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。
注意:code_url有效期为2小时,过期后扫码不能再发起支付。
流程图:
- 1、商户生成订单
- 2、商户调用微信下单接口,获取预交易的链接
- 3、商户将链接生成二维码图片,展示给用户;(码中包含,价格,收款方,订单号)
- 4、用户支付并确认
- 5、支付结果通知:
- 微信异步通知商户支付结果,商户告知微信支付接收情况
- 商户如果没有收到通知,可以调用接口,查询支付状态
- 6、如果支付成功,发货,修改订单状态
在前面的业务中,我们已经完成了:
- 1、生成订单
接下来,我们需要做的是:
- 2、调用微信接口,生成链接。
- 3、并且生成二维码图片
1)创建PayConfig
package com.leyou.order.config;
import com.github.wxpay.sdk.WXPayConfig;
import lombok.Data;
import java.io.InputStream;
@Data
public class PayConfig implements WXPayConfig {
private String appID; //公众账号ID
private String mchID; //商户号
private String key; //生成签名的密钥
private int httpConnectTimeoutMs; //连接超时时间
private int httpReadTimeoutMs; //读取超时时间
private String notifyUrl;// 下单通知回调地址
@Override
public InputStream getCertStream() {
return null;
}
}
2)创建上述对应的配置文件
pay:
appId: wx8397f8696b538317
mchId: 1473426802
key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
connectTimeoutMs: 5000
readTimeoutMs: 10000
notifyUrl: http://k4v7yt.natappfree.cc/notify/wxpay
3)自定义WXPayConfiguration类封装PayConfig
package com.leyou.order.config;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.Basic;
@Configuration
public class WXPayConfiguration {
@Bean
@ConfigurationProperties(prefix = "ly.pay")
public PayConfig payConfig(){
return new PayConfig();
}
@Bean
public WXPay wxPay(PayConfig payConfig){
return new WXPay(payConfig, WXPayConstants.SignType.HMACSHA256);
}
}
4)支付工具类PayHelper
package com.leyou.order.utils;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.order.config.PayConfig;
import com.leyou.order.config.WXPayConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component //将其添加到Spring当中
@Slf4j
public class PayHelper {
@Autowired
private WXPay wxPay;
@Autowired
private PayConfig config;
public String createPayUrl(Long orderId, Long totalPay, String description) {
try {
HashMap<String, String> data = new HashMap<>();
//描述
data.put("body", description);
//订单号
data.put("out_trade_no", orderId.toString());
//货币(默认就是人民币)
//data.put("fee_type", "CNY");
//总金额
data.put("total_fee", totalPay.toString());
//调用微信支付的终端ip
data.put("spbill_create_ip", "127.0.0.1");
//回调地址
data.put("notify_url", config.getNotifyUrl());
//交易类型为扫码支付
data.put("trade_type", "NATIVE");
//利用wxPay工具,完成下单
Map<String, String> result = this.wxPay.unifiedOrder(data);
//判断通信的标识
String return_code = result.get("return_code");
if(WXPayConstants.FAIL.equals(return_code)){
//通信失败
log.error("[微信下单] 微信下单通信失败,失败原因:{}",result.get("return_msg"));
throw new LyException(ExceptionEnum.WX_PAY_ORDER_FAIL);
}
//判断业务标识
String result_code = result.get("result_code");
if(WXPayConstants.FAIL.equals(result_code)){
//通信失败
log.error("[微信下单] 微信下单业务失败,错误码:{},错误原因:{}",result.get("err_code"),result.get("err_code_des"));
throw new LyException(ExceptionEnum.WX_PAY_ORDER_FAIL);
}
//下单成功,获取支付连接
String url = result.get("code_url");
return url;
} catch (Exception e) {
log.error("【微信下单】创建预交易订单异常", e);
return null;
}
}
}
5)编写OrderController的createOrderUrl方法
/*
创建支付链接
*/
@GetMapping("/url/{id}")
public ResponseEntity<String> createPayUrl(@PathVariable("id") Long orderId ){
return ResponseEntity.ok(orderService.createPayUrl(orderId));
}
6)完善OrderService
ORDER_STATUS_ERROR(400,"订单状态异常"),
@Autowired
private PayHelper payHelper;
public String createPayUrl(Long orderId) {
//查询订单 //获取订单总金额
Order order = queryOrderById(orderId);
//判断订单状态
if(order.getOrderStatus().getStatus() != OrderStatusEnum.UN_PAY.value()){
//订单状态异常
throw new LyException(ExceptionEnum.ORDER_STATUS_ERROR);
}
//获取总金额
Long actualPay = order.getActualPay();
actualPay = 1L;
//获取商品描述
OrderDetail orderDetail = order.getOrderDetails().get(0);
String desc = orderDetail.getTitle();
return payHelper.createPayUrl(orderId,actualPay,desc);
}
查询启动运行并测试
刷新支付页面
返回支付链接
(3)生成二维码
1)二维码生成插件qrious
qrious是一款基于HTML5 Canvas的纯JS二维码生成插件。
通过qrious.js可以快速生成各种二维码,你可以控制二维码的尺寸颜色,
还可以将生成的二维码进行Base64编码。
官网
https://github.com/neocotic/qrious
在js目录下引入qrcode.min.js
有pay.html当中已经写好了代码
刷新页面
(4)修改订单状态
1)内网穿透(外网访问本地服务)
内网穿透,也即 NAT 穿透,进行 NAT 穿透是为了使具有某一个特定源 IP 地址和源端口号的数据包不被 NAT 设备屏蔽而正确路由到内网主机。
下面就相互通信的主机在网络中与 NAT 设备的相对位置介绍内网穿透方法。
UDP 内网穿透的实质是利用路由器上的NAT 系统。
NAT 是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型 Internet 接入方式和各种类型的网络中。
NAT可以完成重用地址,并且对于内部的网络结构可以实现对外隐蔽。
免费的内网穿透工具
NATAPP
登录注册
点击复制,即可得到 authtoken 这个authtoken便是您的隧道登录凭证.如这里得到的authtoken为9ab6b9040a624f40
下载客户端
解压
8.运行natapp
natapp支持两种运行方式
a) config.ini方式 (推荐)
根据操作系统下载不同的config.ini文件到刚才下载的natapp.exe同级目录 详见
将第7步得到的authtoken填进去 (其他地方都不填),然后保存
#将本文件放置于natapp同级目录程序将读取[default]段
#在命令行参数模式如natapp -authtoken=xxx等厢同参数将会覆盖掉此配置
[default]
authtoken=9ab6b9040a624f40
#对应一条隧道的authtoken
c1ienttoken=
#对应客户端的c1ienttoken,将会忽略authtoken,若无请留空,
1og=none
#1og且志文件,可以是none 代表不记录或者stdout.代表直接屏幕输出﹐默认为none
1oglevel=INFO
#日志等级DEBUG,INFO,WARNING,ERROR默认为 DEBUG
http_proxy=
#代理设置如http://110.123.10.10:3128
windows下,直接双击natapp.exe 即可.
在Linux/Mac 下 需要先给执行权限
chmod a+x natapp
然后再运行
./natapp
b) cmd -authtoken= 参数方式运行.
windows ,点击开始->运行->命令行提示符 后进入 natapp.exe的目录
运行
natapp -authtoken=9ab6b9040a624f40
linux ,同样给予可执行权限之后,运行
./natapp -authtoken=9ab6b9040a624f40
注意参数输入正确性,不要有多余的空格等!
9.运行成功,都可以得到如下界面:
Tunnel Status Online 代表链接成功
Version 当前客户端版本,如果有新版本,会有提示
Forwarding 当前穿透 网址 或者端口
Web Interface 是本地Web管理界面,可在隧道配置打开或关闭,仅用于web开发测试
Total Connections 总连接数
Avg Conn Time 0.00ms 这里不代表,不代表,不代表 延时,需要注意!
10.将natapp分配的网址(上图Forwarding ),鼠标选定然后复制下来(选定之后单击鼠标右键),在浏览器中访问,可以看到内网穿透成功了!
该网址 就是可以全球访问的网址,可以发给您的小伙伴试试 😃
2)在ly-order当中重新定义一个controller
package com.leyou.order.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("notify")
public class NotifyController {
}
3)修改MVC映射路径
package com.leyou.order.config;
import com.leyou.order.interceptors.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class MvcConfig implements WebMvcConfigurer {
@Autowired
private JwtProperties prop;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserInterceptor(prop))
.addPathPatterns("/order/**")
;
;
}
}
4)完善NotifyController并测试
package com.leyou.order.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("notify")
public class NotifyController {
@GetMapping("{id}")
public String hello(@PathVariable("id") Long id){
return id.toString();
}
}
5)完善订单功能
a、完善application.yml设置对应的路径
b、引入处理xml 的依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml </artifactId>
<version>2.9.6</version>
</dependency>
c、回调
- NotifyController
package com.leyou.order.web;
import com.leyou.order.service.OrderService;
import io.swagger.models.Xml;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("notify")
public class NotifyController {
@Autowired
private OrderService orderService;
/*
微信支付的成功回调
*/
@PostMapping(value = "pay",produces = "application/xml")
public Map<String,String> hello(@RequestBody Map<String,String> result){
//处理回调
orderService.handleNotify(result);
//返回成功
Map<String,String> msg = new HashMap<>();
msg.put("return_code","SUCCESS");
msg.put("return_msg","OK");
return msg;
}
}
- OrderService
- 封装对应PayHelper部分代码为方法
数据的校验
- 封装对应PayHelper部分代码为方法
package com.leyou.order.utils;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.order.config.PayConfig;
import com.leyou.order.config.WXPayConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component //将其添加到Spring当中
@Slf4j
public class PayHelper {
@Autowired
private WXPay wxPay;
@Autowired
private PayConfig config;
public String createPayUrl(Long orderId, Long totalPay, String description) {
try {
HashMap<String, String> data = new HashMap<>();
//描述
data.put("body", description);
//订单号
data.put("out_trade_no", orderId.toString());
//货币(默认就是人民币)
//data.put("fee_type", "CNY");
//总金额
data.put("total_fee", totalPay.toString());
//调用微信支付的终端ip
data.put("spbill_create_ip", "127.0.0.1");
//回调地址
data.put("notify_url", config.getNotifyUrl());
//交易类型为扫码支付
data.put("trade_type", "NATIVE");
//利用wxPay工具,完成下单
Map<String, String> result = this.wxPay.unifiedOrder(data);
//判断通信和业务标识
isSuccess(result);
//下单成功,获取支付连接
String url = result.get("code_url");
return url;
} catch (Exception e) {
log.error("【微信下单】创建预交易订单异常", e);
return null;
}
}
public void isSuccess(Map<String, String> result) {
//判断通信的标识
String return_code = result.get("return_code");
if (WXPayConstants.FAIL.equals(return_code)) {
//通信失败
log.error("[微信下单] 微信下单通信失败,失败原因:{}", result.get("return_msg"));
throw new LyException(ExceptionEnum.WX_PAY_ORDER_FAIL);
}
//判断业务标识
String result_code = result.get("result_code");
if (WXPayConstants.FAIL.equals(result_code)) {
//通信失败
log.error("[微信下单] 微信下单业务失败,错误码:{},错误原因:{}", result.get("err_code"), result.get("err_code_des"));
throw new LyException(ExceptionEnum.WX_PAY_ORDER_FAIL);
}
}
}
签名校验
INVALID_SIGN_ERROR(400,"无效的签名异常"),
public void isValidSing(Map<String, String> data) {
try {
//重新生成签名
String sign1 = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.HMACSHA256);
String sign2 = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5);
//重新生成签名和传过来的签名做比较
String sign = data.get("sign");
if(!StringUtils.equals(sign,sign1) && !StringUtils.equals(sign,sign2)){
//签名有误,抛出异常
throw new LyException(ExceptionEnum.INVALID_SIGN_ERROR);
}
}catch (Exception e){
throw new LyException(ExceptionEnum.INVALID_SIGN_ERROR);
}
}
INVALID_ORDER_PARAM(400,"订单参数异常"),
UPDATE_ORDER_STATUS_ERROR(500,"更新订单状态失败"),
- 继续完善OrderService当中的handleNotify
public void handleNotify(Map<String, String> result) {
// 数据校验
payHelper.isSuccess(result);
// 校验签名
payHelper.isValidSing(result);
// 检验金额
String totalFeeStr = result.get("total_fee");
String tradeNo = result.get("out_trade_no");
if (StringUtils.isEmpty(totalFeeStr) || StringUtils.isEmpty(tradeNo)) {
throw new LyException(ExceptionEnum.INVALID_ORDER_PARAM);
}
// 获取微信支付结果中的金额
Long totalFee = Long.valueOf(totalFeeStr);
//获取订单金额
Long orderId = Long.valueOf(tradeNo);
Order order = orderMapper.selectByPrimaryKey(orderId);
// TODO 这里应该是判断是否等于 order.getActualPay()才对,因为前面支付测试是1分钱,所以这里也是一分钱
if (totalFee != /*order.getActualPay()*/ 1L) {
//微信支付金额与订单金额不符
throw new LyException(ExceptionEnum.INVALID_ORDER_PARAM);
}
//修改订单状态
//
OrderStatus status = new OrderStatus();
status.setStatus(OrderStatusEnum.PAYED.value());
status.setOrderId(orderId);
status.setPaymentTime(new Date());
int count = statusMapper.updateByPrimaryKeySelective(status);
if(count != 1){
throw new LyException(ExceptionEnum.UPDATE_ORDER_STATUS_ERROR);
}
}
- 运行测试
尝试支付
数据库当中也显示支付成功
6)查询订单状态跳转页面
a、分析页面数据
b、实现后台接口
OrderController当中的queryOrderState
@GetMapping("/state/{id}")
public ResponseEntity<Integer> queryOrderState(@PathVariable("id") Long orderId ){
return ResponseEntity.ok(orderService.queryOrderState(orderId).getValue());
}
OrderService当中queryOrderState
- 创建新的状态枚举
package com.leyou.order.enums;
public enum PayState {
NOT_PAY(0),
SUCCESS(1),
FAIL(2)
;
PayState(int value){
this.value = value;
}
int value;
public int getValue(){
return value;
}
}
- 完善OrderService当中queryOrderState方法
public PayState queryOrderState(Long orderId) {
//查询订单状态
OrderStatus orderStatus = statusMapper.selectByPrimaryKey(orderId);
Integer status = orderStatus.getStatus();
//判断是否支付
if(status != OrderStatusEnum.UN_PAY.value()){
//如已支付,就是真的支付
return PayState.SUCCESS;
}
//如果是未支付,也可能是支付了但是延迟的,所以不确定,必须去微信查询支付状态
payHelper.queryPayState(orderId);
return null;
}
- 完善payHelper当中的queryPayState
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderStatusMapper statusMapper;
public PayState queryPayState(Long orderId) {
try {
//组织请求参数
HashMap<String, String> data = new HashMap<>();
//订单号
data.put("out_trade_no", orderId.toString());
//货币(默认就是人民币)
Map<String, String> result = wxPay.orderQuery(data);
//校验通信状态
isSuccess(result);
//校验签名
isValidSing(result);
//校验金额
String totalFeeStr = result.get("total_fee");
String tradeNo = result.get("out_trade_no");
if (StringUtils.isEmpty(totalFeeStr) || StringUtils.isEmpty(tradeNo)) {
throw new LyException(ExceptionEnum.INVALID_ORDER_PARAM);
}
// 获取微信支付结果中的金额
Long totalFee = Long.valueOf(totalFeeStr);
//获取订单金额
Order order = orderMapper.selectByPrimaryKey(orderId);
// TODO 这里应该是判断是否等于 order.getActualPay()才对,因为前面支付测试是1分钱,所以这里也是一分钱
if (totalFee != /*order.getActualPay()*/ 1L) {
//微信支付金额与订单金额不符
throw new LyException(ExceptionEnum.INVALID_ORDER_PARAM);
}
/*
查询状态
*/
String state = result.get("trade_state");
if("SUCCESS".equals(state)){
//支付成功
//修改订单状态
OrderStatus status = new OrderStatus();
status.setStatus(OrderStatusEnum.PAYED.value());
status.setOrderId(orderId);
status.setPaymentTime(new Date());
int count = statusMapper.updateByPrimaryKeySelective(status);
if(count != 1){
throw new LyException(ExceptionEnum.UPDATE_ORDER_STATUS_ERROR);
}
return PayState.SUCCESS;
}
if("NOTPAY".equals(state) || "USERPAYING".equals(state)){
return PayState.NOT_PAY;
}
return PayState.FAIL;
}catch (Exception e){
return PayState.NOT_PAY;
}
}
- 刷新页面
更多推荐
所有评论(0)