# example-ill-dubbo **Repository Path**: fluagen/example-ill-dubbo ## Basic Information - **Project Name**: example-ill-dubbo - **Description**: dubbo 微服务 demo - **Primary Language**: Unknown - **License**: MulanPSL-1.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2017-06-28 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 订单服务demo 我们这里展示如何通过dubbo微服务架构搭建一个订单服务,我们采用spring boot + dubbo 技术路线。 在开始之前,你需要检查你的java和maven是否可用: ``` $ java -version java version "1.8.0_101" Java(TM) SE Runtime Environment (build 1.8.0_101-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode) ``` ``` $ mvn -v Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00) Maven home: /home/majie/env/apache-maven-3.3.9 Java version: 1.8.0_101, vendor: Oracle Corporation ``` ## 1. 项目结构 demo中包含有2个工程: * ill-server 接入层服务 * ill-order-service dobbu服务层 其中,ill-order-service项目我们采用maven多模块的方式,在ill-order-service下分别有2个module: * ill-order-service-api 订单服务接口,也即Provider API * ill-order-service-provider 订单服务实现 ## 2. 安装 1.下载ill-server和ill-order-service两个工程 2.编译安装ill-order-service 在ill-order-service目录下运行 ``` mvn install ``` 3.编译安装ill-server 在ill-server目录下运行 ``` mvn install ``` ## 3.运行 1.启动dubbo服务 在ill-order-service-provider模块下,启动入口为: ill-order-service-provider/src/main/java/com/calis/ill/order/App.java ```java package com.calis.ill.order; import java.util.concurrent.CountDownLatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ImportResource; import org.springframework.transaction.PlatformTransactionManager; //@EnableTransactionManagement @SpringBootApplication @ImportResource({"classpath:dubbo-provider.xml"}) public class App { private static final Logger logger = LoggerFactory.getLogger(App.class); @Bean public CountDownLatch closeLatch() { return new CountDownLatch(1); } @Bean public Object testBean(PlatformTransactionManager platformTransactionManager){ logger.info(">>>>>>>>>>" + platformTransactionManager.getClass().getName()); return new Object(); } public static void main(String[] args) throws InterruptedException { ApplicationContext ctx = new SpringApplicationBuilder().sources(App.class).web(false).run(args); logger.info("ill order provider 启动!"); CountDownLatch closeLatch = ctx.getBean(CountDownLatch.class); closeLatch.await(); } } ``` 不需要配置,直接Run App类启动dubbo服务 2.启动接入层服务 同dubbo服务启动方式相同,也是直接Run App类启动服务 ill-server/src/main/java/com/calis/ill/server/App.java ```java package com.calis.ill.server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ImportResource; @SpringBootApplication @ImportResource({"classpath:dubbo-consumer.xml"}) public class App { private static final Logger logger = LoggerFactory.getLogger(App.class); public static void main(String[] args){ SpringApplication.run(App.class, args); logger.info("ill server 启动!"); } } ``` ## 4.如何使用 本demo实现了一个生成订单服务的业务场景,提供了创建查询用户、商品、订单服务,并且实现了创建订单时的事务控制。 对外服务都是REST风格,对外暴露的REST接口都可以从接入层的controller包中查看到。 我们先来准备生成订单时需要的数据 ``` //创建张三用户,并且他有1000元的资金 curl --header "Content-Type:application/json" -X POST --data '{"account":"zhangsan","username":"zhangsan","password":"1111111", "balance":"1000"}' http://localhost:8080/user/add //创建李四用户,并且他有10000元的资金 curl --header "Content-Type:application/json" -X POST --data '{"account":"lisi","username":"lisi","password":"1111111", "balance":"10000"}' http://localhost:8080/user/add //增加商品 海尔冰箱,该商品单价为2300元,库存为100 curl --header "Content-Type:application/json" -X POST --data '{"title":"海尔冰箱","code":"haier-bx-12345","price":"2300", "stock":"100"}' http://localhost:8080/p/add //增加商品 海尔洗衣机,该商品单价为3300元,库存为100 curl --header "Content-Type:application/json" -X POST --data '{"title":"海尔洗衣机","code":"haier-xyj-12345","price":"3300", "stock":"100"}' http://localhost:8080/p/add ``` 到这里,我们把数据准备好了,下面来生成订单 ``` //李四购买了一台海尔冰箱和一台海尔洗衣机,订单总价为5600元 curl --header "Content-Type:application/json" -X POST --data '[{"code":"haier-bx-12345","quantity":"1"},{"code":"haier-xyj-12345","quantity":"1"}]' http://localhost:8080/lisi/order/create ``` 如果订单生成成功后,商品的库存应该减少1台,同时李四的资金应该减少5600元 ``` //查询李四用户信息 curl http://localhost:8080/user/lisi ``` 查询李四用户返回的信息为 >{"account":"lisi","username":"lisi","balance":4400.00} ``` //查询商品信息 curl http://localhost:8080/p/all ``` 查询商品返回的信息为 >[{"title":"海尔冰箱","price":2300.0,"createTime":1479472537478,"code":"haier-bx-12345","stock":99}, >{"title":"海尔洗衣机","price":3300.0,"createTime":1479472539099,"code":"haier-xyj-12345","stock":99}] ``` //查询李四的订单 curl http://localhost:8080/lisi/order ``` 下面我们来测试下事务的支持,这次我们来生成张三的订单。 ``` //张三购买了一台海尔冰箱和一台海尔洗衣机,订单总价为5600元 curl --header "Content-Type:application/json" -X POST --data '[{"code":"haier-bx-12345","quantity":"1"},{"code":"haier-xyj-12345","quantity":"1"}]' http://localhost:8080/zhangsan/order/create ``` 返回的结果是 >{"timestamp":1479473225201,"status":500,"error":"Internal Server Error","exception":"java.lang.RuntimeException","message":"Balance is not enough","path":"/zhangsan/order/create"} 由于订单总价为5600元,但是张三的账户里只有1000元,所以张三的订单生成失败。 订单生成失败后,张三的资金和商品的库存数量都不应该减少。 ``` //查询张三用户信息 curl http://localhost:8080/user/zhangsan ``` 查询张三用户返回的信息为 >{"account":"zhangsan","username":"zhangsan","balance":1000.00} ``` //查询商品信息 curl http://localhost:8080/p/all ``` 查询商品返回的信息为 >[{"title":"海尔冰箱","price":2300.0,"createTime":1479472537478,"code":"haier-bx-12345","stock":99}, >{"title":"海尔洗衣机","price":3300.0,"createTime":1479472539099,"code":"haier-xyj-12345","stock":99}] 订单服务接口实现类OrderServiceImpl ```java package com.calis.ill.order.service.impl; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.calis.ill.order.entity.Order; import com.calis.ill.order.entity.OrderItem; import com.calis.ill.order.entity.Product; import com.calis.ill.order.entity.User; import com.calis.ill.order.repository.OrderRepository; import com.calis.ill.order.repository.ProductRepository; import com.calis.ill.order.repository.UserRepository; import com.calis.ill.order.service.api.OrderService; import com.calis.ill.order.service.api.vo.OrderItemVO; import com.calis.ill.order.service.api.vo.OrderVO; import com.fasterxml.jackson.databind.ObjectMapper; @Service("orderService") public class OrderServiceImpl implements OrderService { @Autowired OrderRepository repo; @Autowired UserRepository userRepo; @Autowired ProductRepository productRepo; ObjectMapper mapper = new ObjectMapper(); @Transactional public void create(String account, List items) throws Exception { Order order = new Order(); order.setSn(UUID.randomUUID().toString()); double totalPrice = 0; List orderItems = new ArrayList(); List products = new ArrayList(); for (OrderItemVO item : items) { OrderItem o = new OrderItem(); o.setCode(item.getCode()); o.setQuantity(item.getQuantity()); o.setOrder(order); Product p = productRepo.findByCode(o.getCode()); Long stock = p.getStock() - o.getQuantity(); if (stock < 0) { throw new RuntimeException(p.getTitle() + " is not enough product"); } p.setStock(stock); products.add(p); totalPrice += p.getPrice() * o.getQuantity(); orderItems.add(o); } productRepo.save(products); order.setOrderItems(orderItems); order.setTotalPrice(totalPrice); User user = userRepo.findByAccount(account); BigDecimal balance = user.getBalance().subtract(new BigDecimal(totalPrice)); if (balance.doubleValue() < 0) { throw new RuntimeException("Balance is not enough"); } user.setBalance(balance); userRepo.save(user); order.setUser(user); order.setStatus(1); order.setCreateTime(new Date()); repo.save(order); } public List getMyOrders(String account) throws Exception { List rst = new ArrayList(); List orders = repo.findByUser_Account(account); for (Order order : orders) { OrderVO vo = new OrderVO(); vo.setCreateTime(order.getCreateTime()); vo.setSn(order.getSn()); vo.setStatus(order.getStatus()); vo.setTotalPrice(order.getTotalPrice()); List itemVOs = new ArrayList(); for (OrderItem item : order.getOrderItems()) { OrderItemVO itemVO = new OrderItemVO(); itemVO.setCode(item.getCode()); itemVO.setQuantity(item.getQuantity()); itemVOs.add(itemVO); } vo.setOrderItems(itemVOs); rst.add(vo); } return rst; }; } ``` 订单服务接口实现类OrderServiceImpl中可以看到,创建订单服务是受事务控制的,所以张三的资金和商品的数量都没有减少。