本文共 18538 字,大约阅读时间需要 61 分钟。
之前章节开发的接口都是为了下订单接口的开发做了铺垫,下订单的接口内部将调用这些接口,是一个涉及到4-5个微服务的重量级接口.
可以看到该接口涉及的微服务有:server-user、server-goods、server-pay和server-order服务.
com.ccm assembly-mysql 1.0.0 org.springframework.cloud spring-cloud-starter-openfeign
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); }}
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
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)); }}
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() { Listpars = 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(); }}
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
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 ListpayOrderReqList, @ApiParam(hidden = true) @RequestHeader(name = "ccm-userId") Long userId) { orderService.order(payOrderReqList,userId); return ResultSet.success(); }}
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;}
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(ListpayOrderReqList, Long userId);}
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(ListpayOrderReqList, 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); }}
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); }}
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 ListreduceStockReqList); @ApiOperation(value = "根据id获取sku") @GetMapping(value = "goods/selectByIdList") ResultSet
> selectByIdList(@RequestParam List idList);}
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") ResultSetpay(@RequestHeader(name = "ccm-userId") Long userId,@RequestParam BigDecimal payMoney);}
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;}
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;}
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;}
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;}
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);}
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") ListorderSkuList);}
insert into order_info id, amount_money, `status`, user_id, flowing_water_id, update_time, create_time,#{id}, #{amountMoney}, #{status}, #{userId}, #{flowingWaterId}, now(), now(),
insert into order_sku ( sku_id, sku_number, sku_money, order_id, create_time ) values ( #{item.skuId}, #{item.skuNumber}, #{item.skuMoney}, #{item.orderId}, now() )
您的点赞、收藏、转发和关注是我持续创作的动力!
源码地址:
转载地址:http://kutli.baihongyu.com/