微服务拆分及商品服务案例

在微服务架构中,需要我们对服务进行拆分,各个服务之间需要满足高内聚、低耦合。每个服务之间的改动不收影响。

如何进行拆分?

要了解服务如何拆分,我们要明白项目的启点和终点在哪。
起点: - 当前项目结构状态,是对已有的项目进行改进,还是需要从零开发的新项目。
终点: - 好的结构不是设计出来的,而是进化来的。 一直在进化中…

是否适合上微服务?

在一下业务形态上并不适合微服务结构:

  • 系统中包含很多很强事务事务场景的。
  • 业务相对稳定,迭代周期长的。
  • 访问压力不大,可用性要求不高。
    在这里插入图片描述
    以点餐系统为例,我们根据业务形态进行服务拆分:商品服务和订单服务。

以代码为例更能清楚直观的了解微服务,可以点击右侧使用到的数据库表结构:商品和订单表

商品服务项目搭建

1、新建一个商品工程-product
在这里插入图片描述

2、注册配置:

spring:
  application:
    name: product
eureka:
  client:
    service-url:
        defaultZone: http://localhost:8761/eureka

3、启动类注解添加:@EnableDiscoveryClient

@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication {

   public static void main(String[] args) {
      SpringApplication.run(ProductApplication.class, args);
   }

启动项目,在注册中心查看是否被注册
在这里插入图片描述
服务成功注册,再引入其依赖,这里使用ORM框架使用的是springData JPA,依赖如下:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
</dependency>

数据库配置:

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password:
    url: jdbc:mysql://127.0.0.1/springcloud?characterEncoding=utf-8&useSSL=false
  jpa:
    show-sql: true

配置完成,启动项目进行测试。

后端开发

1、创建商品与数据库对应的实体类。

  • @Data是lombok的注解,省去写get\set方法,@Entity和@Id注解是实体类与数据库表对应注解。
@Data
@Entity
public class ProductInfo {
    @Id
    private String productId;

    private String productName;

    private BigDecimal productPrice;

    private Integer productStock;

    private String productDescription;

    private String productIcon;

    private Integer productStatus;

    private Integer categoryType;

    private Date createTime;

    private Date updateTime;
}

类目数据库实体类:

  • 这里的id是自增的,需要添加注解 @GeneratedValue
@Data
@Entity
public class ProductCategory {
    @Id
    @GeneratedValue
    private Integer categoryId;

    private String categoryName;

    private Integer categoryType;

    private Date createTime;

    private Date updateTime;

}

2、在respository包下新建一个ProductInfoRepository接口:查询所有在架商品

public interface ProductInfoRepository   extends JpaRepository<ProductInfo,String>{
   List<ProductInfo> findByProductStatus(Integer productStatus);
}

查询所有类目:

public interface ProductCategoryRepository extends JpaRepository<ProductCategory,Integer> {
    List<ProductCategory> findBycategoryTypeIn(List<Integer> categoryTypeList);
}

3、Service层接口实现:

商品接口及实现

public interface ProductService {
    /**
     * 查询所有商品在架列表
     * @return
     */
    List<ProductInfo> findUpAll();
}
@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductInfoRepository productInfoRepository;

    @Override
    public List<ProductInfo> findUpAll() {
        return productInfoRepository.findByProductStatus(ProductStatusEnum.UP.getCode());
    }
}

类目接口及实现

public interface CategoryService {
    public List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList);
}
实现类
@Service
public class CategoryServiceImpl implements CategoryService {
    @Autowired
    private ProductCategoryRepository productCategoryRepository;
    @Override
    public List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList) {
        return productCategoryRepository.findBycategoryTypeIn( categoryTypeList);
    }
}

4、Controller层

@RestController
@RequestMapping("/product")
public class ProductController {
   @Autowired
   private ProductService productService;
   @Autowired
   private CategoryService categoryService;

    /**
     *
     * @return
     */
    @RequestMapping("list")
    public ResultVO<ProductVO> list () {
        // 1、查询所有在架的商品
        List<ProductInfo> productInfoList = productService.findUpAll();
        // 2、 获取类目type列表
        List<Integer> categoryTypeList = productInfoList.stream()
                .map(ProductInfo::getCategoryType).collect(Collectors.toList());
        // 3、从数据库查询类目
        List<ProductCategory> productCategoryList = categoryService.findByCategoryTypeIn(categoryTypeList);
       // 4、构造数据
        List<ProductVO> productVOList = new ArrayList<>();
        for (ProductCategory productCategory : productCategoryList) {
            ProductVO productVO = new ProductVO();
            productVO.setCategoryName(productCategory.getCategoryName());
            productVO.setCategoryType(productCategory.getCategoryType());
            List<ProductInfoVO> productInfoVOList = new ArrayList<>();
            for (ProductInfo productInfo : productInfoList) {
               if (productInfo.getCategoryType().equals(productCategory.getCategoryType())) {
                   ProductInfoVO productInfoVO = new ProductInfoVO();
                   BeanUtils.copyProperties(productInfo,productInfoVO);
                   productInfoVOList.add(productInfoVO);
               }
            }
            productVO.setProductInfoVOList(productInfoVOList);
            productVOList.add(productVO);
        }
        ResultVO resultVO = new ResultVO();
        resultVO.setData(productVOList);
        resultVO.setCode(0);
        resultVO.setMessage("成功");
        return resultVO;
    }
}

5、在项目架构中视图层对象(VO)和持久层对象(PO)会区分开发,我们这里需要根据需要返回的数据定义商品和类目的实体类。
结果对象实体类:

/**
 * HTTP 请求返回的最外层对象
 * @param <T>
 */
@Data
public class ResultVO<T> {
    /**
     * 错误码
     */
    private Integer code;
    /**
     * 提示信息
     */
    private String message;
    /**
     * 具体内容
     */
    private T data;
}

类目对象实体类

  • 如果json返回的是name,后端使用categoryName更能清楚的表达语义,可以使用 @JsonProperty注解,这样返回的json数据就会转换为name属性。
@Data
public class ProductVO {
    @JsonProperty("name")
    private String categoryName;
    @JsonProperty("type")
    private Integer categoryType;
    @JsonProperty("foods")
    List<ProductInfoVO> productInfoVOList;

}

商品对象实体类

@Data
public class ProductInfoVO {
    @JsonProperty("id")
    private String productID;
    @JsonProperty("name")
    private String productName;
    @JsonProperty("price")
    private BigDecimal productPrice;
    @JsonProperty("description")
    private String productDescription;
    @JsonProperty("icon")
    private String productIcon;
}

6、这里再查询在架商品时,我们不是直接在程序中进行0,1硬编码,可以通过创建枚举来表示商品上下架状态。

/**
 * 商品上下架装态
 */
@Getter
public enum ProductStatusEnum {
    UP(0,"在架"),
    DOWN(1,"下架"),
    ;
    private Integer code;

    private String message;

    ProductStatusEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值