Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)二十二(下单和微信支付(1)

}

在这里插入图片描述

在这里插入图片描述

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 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 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 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 {

}

在这里插入图片描述

在这里插入图片描述

package com.leyou.order.mapper;

import com.leyou.common.mapper.BaseMapper;

import com.leyou.order.pojo.OrderDetail;

public interface OrderDetailMapper extends BaseMapper {

}

在这里插入图片描述

在这里插入图片描述

package com.leyou.order.mapper;

import com.leyou.common.mapper.BaseMapper;

import com.leyou.order.pojo.OrderStatus;

public interface OrderStatusMapper extends BaseMapper {

}

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碰撞(由datacenterworkerld作区分),

并且效率较高。

经测试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 addressList = new ArrayList() {

{

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 querySkuBySpuId(@RequestParam(“ids”) List 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{

@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 decreaseStock(@RequestBody List carts){

goodsService.decreaseStock(carts);

return ResponseEntity.status(HttpStatus.NO_CONTENT).build();

}

  • GoodsService

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

@Transactional

public void decreaseStock(List 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 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 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 ids = numMap.keySet();

//根据id查询sku

List skus = goodsClient.querySkuBySpuId(new ArrayList<>(ids));

//准备orderDetail

List 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 carts = orderDTO.getCarts();

goodsClient.decreaseStock(carts);

return orderId;

}

}

2.0.7 测试创建订单

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.订单

===============================================================

(1)点击支付后会跳转到支付页面


在这里插入图片描述

(2)实现上述所对应的接口(先实现查询订单)


(a)OrderController当中queryOrderById方法

在这里插入图片描述

@GetMapping(“{id}”)

public ResponseEntity 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 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 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

在这里插入图片描述

Java面试核心知识点笔记

其中囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

Java中高级面试高频考点整理

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

最后分享Java进阶学习及面试必备的视频教学

蚂蚁金服(Java研发岗),26岁小伙斩获三面,收获Offer定级P6

//img-blog.csdnimg.cn/aead30a115f14dfbb62ee1a336f80e25.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6JOd55uS5a2QaXRibHVlYm94,size_20,color_FFFFFF,t_70,g_se,x_16)

@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

在这里插入图片描述

Java面试核心知识点笔记

其中囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。

[外链图片转存中…(img-vECC6YLV-1714388948346)]

Java中高级面试高频考点整理

[外链图片转存中…(img-BYxHokRe-1714388948347)]

[外链图片转存中…(img-aGtkarYV-1714388948347)]

最后分享Java进阶学习及面试必备的视频教学

[外链图片转存中…(img-TV36iLr2-1714388948347)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本文介绍了一个基于Spring BootSpring CloudVue前后端分离项目实战。这个项目是一个简单的在线商城,包含了用户注册、登录、商品展示、购物车、订单管理等功能。通过这个项目,读者可以深入理解前后端分离的架构模式和互联网应用的开发方式。 首先,文章介绍了前后端分离的基本概念和优势。前后端分离是将应用的前端和后端代码分开来开发,使得前端和后端具有独立的开发周期和技术栈,进而提高了开发效率和代码质量。同时,前后端分离还可以提供更好的用户体验和灵活性,对于互联网应用来说尤为重要。 接下来,文章介绍了项目的架构和技术栈。项目采用了Spring BootSpring Cloud框架来实现后端代码,采用MyBatis作为ORM框架和Redis作为缓存中间件。同时,项目还采用了Vue.js作为前端框架和Element UI组件库来实现前端页面。通过这些开源框架和组件,可以快速搭建一个前后端分离的互联网应用。 然后,文章介绍了项目的核心功能和代码实现。在用户注册和登录方面,项目采用了Spring Security框架和JWT令牌来实现用户认证和授权,保证了用户信息的安全性。在商品展示和购物车方面,项目采用了Vue.js来实现前端页面和事件处理。在订单管理方面,项目采用了MyBatis Plus来实现订单数据的持久化和分页查询。 最后,文章介绍了项目的测试和优化。通过对项目的压力测试和性能测试,文章发现项目还存在一些性能瓶颈和安全隐患,可以通过优化数据库查询、缓存配置和代码实现来提高应用的性能和安全性。 总之,这篇文章介绍了一个基于Spring BootSpring CloudVue前后端分离项目实战,通过实现一个在线商城的功能,展示了前后端分离的开发模式和互联网应用的开发技术栈。本文可以作为前后端分离开发的入门教程,也可以作为互联网应用开发的参考文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值