博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用SpringCloud Alibaba搭建属于自己的微服务(三十四)~业务开发~下订单核心接口开发
阅读量:4203 次
发布时间:2019-05-26

本文共 18538 字,大约阅读时间需要 61 分钟。

一.概述

之前章节开发的接口都是为了下订单接口的开发做了铺垫,下订单的接口内部将调用这些接口,是一个涉及到4-5个微服务的重量级接口.

二.下订单接口伪代码

可以看到该接口涉及的微服务有:server-user、server-goods、server-pay和server-order服务.

在这里插入图片描述

三.新建server-order微服务

1.创建maven工程.

在这里插入图片描述

2.server-order.pom中引入maven依赖.

com.ccm
assembly-mysql
1.0.0
org.springframework.cloud
spring-cloud-starter-openfeign

3.编写服务启动类.

package com.ccm.server.order;import org.mybatis.spring.annotation.MapperScan;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 org.springframework.context.annotation.ComponentScan;import springfox.documentation.swagger2.annotations.EnableSwagger2;/** * @Description server-order服务启动类 * @Author ccm * @CreateTime 2020/8/14 9:47 */@EnableFeignClients@EnableDiscoveryClient //注册中心客户端@ComponentScan(basePackages = "com.ccm")@EnableSwagger2@SpringBootApplication //声明为一个启动类@MapperScan(basePackages = "com.ccm.server.order.dao.mysql.mapper")public class ServerOrderApplication {
public static void main(String[] args) {
SpringApplication.run(ServerOrderApplication.class,args); }}

4.编写bootstrap.yml配置文件.

server:  port: 7677  #服务端口spring:  application:    name: server-order #服务名称  cloud:    nacos:      discovery:        server-addr: 47.96.131.185:8849      config:        server-addr: 47.96.131.185:8849  #nacos config配置中心ip和端口        file-extension: yaml  #文件扩展名格式,针对于默认的{spring.application.name}-${profile}.${file-extension:properties}配置        enabled: true #开启或关闭配置中心  datasource:    username: root    password: Test2016@    url: jdbc:mysql://47.96.131.185:3306/order?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true    type: com.alibaba.druid.pool.DruidDataSourcemybatis-plus:  typeAliasesPackage: com.ccm.server.order.dao.mysql.domain  #数据库实体类包  mapper-locations: classpath:mappering/*.xml #xml文件扫描#自定义配置server-order:  serverNumber: 12

5.自定义配置的实体映射.

package com.ccm.server.order.constants;import com.alibaba.fastjson.JSONObject;import lombok.Data;import lombok.extern.slf4j.Slf4j;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;/** * @Description 自定义配置映射实体 * @Author ccm * @CreateTime 2020/08/18 15:01 */@Slf4j@Data@Component@ConfigurationProperties(prefix = "server-order")public class ServerOrderProperties {
private String serverNumber; @PostConstruct public void init() {
log.info("ServerOrderProperties初始化完成......{}", JSONObject.toJSONString(this)); }}

6.swagger配置.

package com.ccm.server.order.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.ParameterBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.schema.ModelRef;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Parameter;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import java.util.ArrayList;import java.util.List;/** * @Description swagger配置 * @Author ccm * @CreateTime 2020/08/14 17:38 */@Configurationpublic class SwaggerConfig {
@Bean public Docket createRestApi() {
List
pars = new ArrayList
(); ParameterBuilder ticketPar = new ParameterBuilder(); ticketPar.name("ccm-token").description("必要参数(白名单接口无需传递)") .modelRef(new ModelRef("string")).parameterType("header") .required(false).build(); //header中的ticket参数非必填,传空也可以 pars.add(ticketPar.build()); return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.ccm.server.order.controller")) //swagger接口扫描包 .paths(PathSelectors.any()).build().globalOperationParameters(pars); } private ApiInfo apiInfo() {
return new ApiInfoBuilder().version("1.0.0") .title("欢迎") .description("光临") .termsOfServiceUrl("www.baidu.com") .build(); }}

7.gateway网关加入server-order微服务的路由.

spring:  cloud:    gateway:      routes: #路由配置        - id: server-order #路由名称,不配默认为UUID          uri: lb://server-order #满足断言的路由到此服务          predicates: #为一个数组,每个规则为并且的关系            - Path=/api-order/** #断言表达式,如果args不写key的,会自动生成一个id,如下会生成一个xxx0的key,值为/foo/*          filters: #请求路由转发前执行的filter,为数组            - StripPrefix=1  #缩写,和name=StripPrefix,args,参数=1是一个意思,该过滤器为路由转发过滤去            - name: AuthFilter

四.业务代码编写

1.控制层

(1).OrderController
package com.ccm.server.order.controller;import com.ccm.common.exception.result.ResultSet;import com.ccm.server.order.controller.req.PayOrderReq;import com.ccm.server.order.service.OrderService;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import io.swagger.annotations.ApiParam;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import javax.validation.Valid;import javax.validation.constraints.Size;import java.util.List;/** *  @Description 订单控制层 *  @Author ccm *  @CreateTime 2020/08/14 14:46 */@Api(tags = "订单控制层")@RestController@RequestMapping(value = "order")public class OrderController {
@Autowired private OrderService orderService; @ApiOperation(value = "下单") @PostMapping public ResultSet order(@Valid @Size(min = 1) @RequestBody List
payOrderReqList, @ApiParam(hidden = true) @RequestHeader(name = "ccm-userId") Long userId) {
orderService.order(payOrderReqList,userId); return ResultSet.success(); }}
(2).PayOrderReq
package com.ccm.server.order.controller.req;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import javax.validation.constraints.NotNull;import java.util.List;/** *  @Description 下订单入参实体 *  @Author ccm *  @CreateTime 2020/08/14 10:52 */@Data@ApiModel(value = "下订单入参实体")public class PayOrderReq {
@ApiModelProperty(value = "商品id") private Long skuId; @ApiModelProperty(value = "下单商品数量") private Integer skuNumber;}

2.业务层

(1).OrderService
package com.ccm.server.order.service;import com.ccm.server.order.controller.req.PayOrderReq;import java.util.List;/** *  @Description 订单业务层 *  @Author ccm *  @CreateTime 2020/08/14 10:10 */public interface OrderService {
/** * @Description 下单 * @Author ccm * @CreateTime 2020/8/20 13:54 * @Params [waitingPayReq, userId] * @Return void */ void order(List
payOrderReqList, Long userId);}
(2).OrderServiceImpl
package com.ccm.server.order.service.impl;import com.alibaba.nacos.client.naming.utils.CollectionUtils;import com.ccm.common.exception.CustomerException;import com.ccm.common.exception.result.ResultSet;import com.ccm.server.order.config.OrderIdGenerator;import com.ccm.server.order.controller.req.PayOrderReq;import com.ccm.server.order.dao.mysql.domain.OrderInfo;import com.ccm.server.order.dao.mysql.domain.OrderSku;import com.ccm.server.order.dao.mysql.mapper.OrderInfoMapper;import com.ccm.server.order.dao.mysql.mapper.OrderSkuMapper;import com.ccm.server.order.feign.ServerGoodsFeign;import com.ccm.server.order.feign.ServerPayFeign;import com.ccm.server.order.feign.req.ReduceStockReq;import com.ccm.server.order.feign.vo.GoodsSkuVO;import com.ccm.server.order.service.OrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;/** *  @Description 订单业务层实现类 *  @Author ccm *  @CreateTime 2020/08/14 10:11 */@Servicepublic class OrderServiceImpl implements OrderService {
@Autowired private OrderSkuMapper orderSkuMapper; @Autowired private OrderInfoMapper orderInfoMapper; @Autowired private ServerGoodsFeign serverGoodsFeign; @Autowired private OrderIdGenerator orderIdGenerator; @Autowired private ServerPayFeign serverPayFeign; @Override @Transactional(rollbackFor = Exception.class) public void order(List
payOrderReqList, Long userId) {
//生成订单号 String orderId = orderIdGenerator.nextOrderId(); //获取商品的详细信息 ResultSet
> resultSet = serverGoodsFeign.selectByIdList(payOrderReqList.stream() .map(PayOrderReq::getSkuId) .collect(Collectors.toList())); List
goodsSkuVOList = ResultSet.getFeignData(resultSet); if(CollectionUtils.isEmpty(goodsSkuVOList) || goodsSkuVOList.size()!=payOrderReqList.size()) {
throw new CustomerException("商品不存在"); } //扣商品库存 List
reduceStockReqList = payOrderReqList.stream() .map(t -> new ReduceStockReq(t.getSkuId(),t.getSkuNumber())) .collect(Collectors.toList()); ResultSet.getFeignData(serverGoodsFeign.reduceStock(reduceStockReqList)); //支付 BigDecimal totalMoney = new BigDecimal(0.0d); for(PayOrderReq payOrderReq:payOrderReqList) {
for(GoodsSkuVO goodsSkuVO:goodsSkuVOList) {
if(payOrderReq.getSkuId().equals(goodsSkuVO.getId())) {
BigDecimal skuNumber = new BigDecimal(payOrderReq.getSkuNumber()); totalMoney = totalMoney.add(goodsSkuVO.getPrice().multiply(skuNumber)); break; } } } String flowingWaterId = ResultSet.getFeignData(serverPayFeign.pay(userId, totalMoney)); //主订单表插入数据 OrderInfo orderInfo = new OrderInfo(); orderInfo.setId(orderId); orderInfo.setAmountMoney(totalMoney); orderInfo.setStatus(1); orderInfo.setUserId(userId); orderInfo.setFlowingWaterId(flowingWaterId); orderInfoMapper.insert(orderInfo); //子订单表插入数据 ArrayList
orderSkuList = new ArrayList<>(); payOrderReqList.forEach(payOrderReq -> { OrderSku orderSku = new OrderSku(); orderSku.setOrderId(orderId); orderSku.setSkuNumber(payOrderReq.getSkuNumber()); orderSku.setSkuId(payOrderReq.getSkuId()); for(GoodsSkuVO goodsSkuVO:goodsSkuVOList) { if(payOrderReq.getSkuId().equals(goodsSkuVO.getId())) { orderSku.setSkuMoney(goodsSkuVO.getPrice()); break; } } orderSkuList.add(orderSku); }); orderSkuMapper.insertList(orderSkuList); }}
(3).OrderIdGenerator
package com.ccm.server.order.config;import com.ccm.server.order.constants.ServerOrderProperties;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;import java.util.Date;import java.util.UUID;/** * @Description 订单id生成器 * @Author ccm * @CreateTime 2020/02/16 15:17 */@Componentpublic class OrderIdGenerator {
private Long lastTimeStamp = 0L; //上次生成订单id的时间戳 @Autowired private ServerOrderProperties serverOrderProperties; /** * @Description 生成订单号 * @Author zhouzhiwu * @CreateTime 2020/2/16 15:17 * @Params [] * @Return java.lang.String */ public String nextOrderId() {
Long timeStamp; synchronized (this.getClass()) {
while(true) {
Long nowTimeStamp = System.currentTimeMillis(); if(!nowTimeStamp.equals(lastTimeStamp)) {
timeStamp = nowTimeStamp; lastTimeStamp = nowTimeStamp; break; } } } String timeStampStr = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date(timeStamp)); StringBuffer orderIdStringBuffer = new StringBuffer(); orderIdStringBuffer.append(timeStampStr) .append(serverOrderProperties.getServerNumber()) .append(UUID.randomUUID().toString()); return orderIdStringBuffer.toString().substring(0,32); }}

3.调用外部服务的feign层.

(1).ServerGoodsFeign
package com.ccm.server.order.feign;import com.ccm.common.exception.result.ResultSet;import com.ccm.server.order.feign.req.ReduceStockReq;import com.ccm.server.order.feign.vo.GoodsSkuVO;import io.swagger.annotations.ApiOperation;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PutMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestParam;import java.util.List;/** *  @Description 调用server-goods服务feign层 *  @Author ccm *  @CreateTime 2020/08/18 15:23 */@FeignClient(name = "server-goods")public interface ServerGoodsFeign {
@ApiOperation(value = "减少库存入参") @PutMapping(value = "goods/reduceStock") ResultSet reduceStock(@RequestBody List
reduceStockReqList); @ApiOperation(value = "根据id获取sku") @GetMapping(value = "goods/selectByIdList") ResultSet
> selectByIdList(@RequestParam List
idList);}
(2).ServerPayFeign
package com.ccm.server.order.feign;import com.ccm.common.exception.result.ResultSet;import com.ccm.server.order.feign.req.ReduceStockReq;import com.ccm.server.order.feign.vo.GoodsSkuVO;import io.swagger.annotations.ApiOperation;import io.swagger.annotations.ApiParam;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.*;import java.util.List;/** *  @Description 调用server-pay服务feign层 *  @Author ccm *  @CreateTime 2020/08/18 15:23 */@FeignClient(name = "server-pay")public interface ServerPayFeign {
@ApiOperation(value = "支付") @PostMapping(value = "pay/pay") ResultSet
pay(@RequestHeader(name = "ccm-userId") Long userId,@RequestParam BigDecimal payMoney);}
(3).ReduceStockReq
package com.ccm.server.order.feign.req;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;/** *  @Description feign调用减少库存入参 *  @Author ccm *  @CreateTime 2020/08/17 14:49 */@NoArgsConstructor@AllArgsConstructor@Datapublic class ReduceStockReq {
private Long skuId; private Integer number;}
(4).GoodsSkuVO
package com.ccm.server.order.feign.vo;import com.alibaba.fastjson.annotation.JSONField;import com.fasterxml.jackson.annotation.JsonFormat;import lombok.Data;import java.util.Date;/** *  @Description feign调用server-goods商品的结果视图 *  @Author ccm *  @CreateTime 2020/08/19 10:48 */@Datapublic class GoodsSkuVO {
private Long id; private String name; private BigDecimal price; private Integer stock; private Date createTime; private Date updateTime;}

3.持久层.

(1).OrderInfo
package com.ccm.server.order.dao.mysql.domain;import lombok.Data;import java.util.Date;/** *  @Description order_info表实体类 *  @Author ccm *  @CreateTime 2020/08/17 10:44 */@Datapublic class OrderInfo {
private String id; private BigDecimal amountMoney; private Integer status; private Long userId; private String flowingWaterId; private Date updateTime; private Date createTime;}
(2).OrderSku
package com.ccm.server.order.dao.mysql.domain;import lombok.Data;import java.util.Date;/** *  @Description order_sku表实体类 *  @Author ccm *  @CreateTime 2020/08/17 10:46 */@Datapublic class OrderSku {
private Long id; private Long skuId; private Integer skuNumber; private BigDecimal skuMoney; private String orderId; private Date createTime;}
(3).OrderInfoMapper
package com.ccm.server.order.dao.mysql.mapper;import com.ccm.server.order.dao.mysql.domain.OrderInfo;/** *  @Description order_info表持久层 *  @Author ccm *  @CreateTime 2020/08/17 10:49 */public interface OrderInfoMapper {
int insert(OrderInfo orderInfo);}
(4).OrderSkuMapper
package com.ccm.server.order.dao.mysql.mapper;import com.ccm.server.order.dao.mysql.domain.OrderSku;import org.apache.ibatis.annotations.Param;import java.util.List;/** *  @Description order_sku表持久层 *  @Author ccm *  @CreateTime 2020/08/17 10:49 */public interface OrderSkuMapper {
int insertList(@Param("list") List
orderSkuList);}
(5).OrderInfoMapper.xml
insert into order_info
id,
amount_money,
`status`,
user_id,
flowing_water_id,
update_time, create_time,
#{id},
#{amountMoney},
#{status},
#{userId},
#{flowingWaterId},
now(), now(),
(6).OrderSkuMapper.xml
insert into order_sku ( sku_id, sku_number, sku_money, order_id, create_time ) values
( #{item.skuId}, #{item.skuNumber}, #{item.skuMoney}, #{item.orderId}, now() )
(7).order.order_info表结构

在这里插入图片描述

(8).order.order_sku表结构

在这里插入图片描述

五.测试

1.数据库基础数据准备

(1).goods.goods_sku增加两个商品

在这里插入图片描述

(2).user.user_info为ccm用户的账户余额到10万

在这里插入图片描述

2.启动gateway、server-user、server-goods、server-pay和server-order服务.在这里插入图片描述

3.打开gateway的swagger界面.

在这里插入图片描述

4.调用下单接口,买一台苹果11和一台华为P30.

在这里插入图片描述

在这里插入图片描述

5.查看数据库的数据变化.

(1).user.user_info表,账户余额被扣除

在这里插入图片描述

(2).pay.pay_flowing_water支付流水表,生成了流水记录

在这里插入图片描述

(3).goods.goods_sku商品表,库存减少了

在这里插入图片描述

(4).order.order_info主订单表,有了一笔主订单

在这里插入图片描述

(5).order.order_sku子订单表,有了两笔子订单

在这里插入图片描述

至此,完事!

您的点赞、收藏、转发和关注是我持续创作的动力!

源码地址:

转载地址:http://kutli.baihongyu.com/

你可能感兴趣的文章
Putty远程服务器的SSH经验
查看>>
内核态与用户态
查看>>
使用mingw(fedora)移植virt-viewer
查看>>
趣链 BitXHub跨链平台 (4)跨链网关“初介绍”
查看>>
C++ 字符串string操作
查看>>
MySQL必知必会 -- 了解SQL和MySQL
查看>>
MySQL必知必会 -- 使用MySQL
查看>>
MySQL必知必会 -- 数据检索
查看>>
MySQL必知必会 -- 排序检索数据 ORDER BY
查看>>
MySQL必知必会 -- 数据过滤
查看>>
MYSQL必知必会 -- 用通配符进行过滤
查看>>
MYSQL必知必会 -- 用正则表达式进行搜索
查看>>
MySQL必知必会 -- 创建计算字段
查看>>
MySQL必知必会 -- 使用数据处理函数
查看>>
MySQL必知必会 -- 数据汇总
查看>>
MySQL必知必会 -- 子查询的使用
查看>>
POJ 3087 解题报告
查看>>
POJ 2536 解题报告
查看>>
POJ 1154 解题报告
查看>>
POJ 1661 解题报告
查看>>