01 商品微服务

数据模型-商品微服务

  商品微服务模块的库表设计:

  • 商品目录
  • 商品

  商品要归属于某个商品目录,通过在category_type字段来将产品product和产品目录product_category关联起来。

-- ----------------------------
-- Table structure for product_category
-- ----------------------------
DROP TABLE IF EXISTS `product_category`;
CREATE TABLE `product_category` (
  `category_id` int(11) NOT NULL AUTO_INCREMENT,
  `category_name` varchar(255) DEFAULT NULL COMMENT '产品目录名称',
  `category_type` int(11) NOT NULL COMMENT '产品目录类型,用于存储特定类型的商品',
  `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of product_category
-- ----------------------------
INSERT INTO `product_category` VALUES ('1', '热饮', '99', '2019-03-20 22:47:41', '2019-03-20 22:47:41');
INSERT INTO `product_category` VALUES ('2', '酒水', '98', '2019-03-20 22:48:13', '2019-03-20 22:48:13');
INSERT INTO `product_category` VALUES ('3', '甜品', '97', '2019-03-20 22:47:51', '2019-03-20 22:47:51');
————————————————
-- ----------------------------
-- Table structure for product
-- ----------------------------
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `product_name` varchar(255) NOT NULL,
  `product_stock` int(11) NOT NULL COMMENT '库存',
  `product_price` decimal(8,2) DEFAULT NULL,
  `product_description` varchar(255) DEFAULT NULL,
  `product_icon` varchar(255) DEFAULT NULL,
  `product_status` tinyint(3) DEFAULT '0' COMMENT '商品状态, 0正常  1下架',
  `category_type` int(11) DEFAULT NULL COMMENT '产品目录',
  `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of product
-- ----------------------------
INSERT INTO `product` VALUES ('1', '拿铁咖啡', '99', '20.99', '咖啡,提神醒脑', null, '0', '99', '2019-03-20 22:49:47', '2019-03-20 22:49:50');
INSERT INTO `product` VALUES ('2', '青岛纯生', '200', '7.50', '啤酒', null, '0', '98', '2019-03-20 22:50:48', '2019-03-20 22:50:55');
INSERT INTO `product` VALUES ('3', '卡布奇诺', '87', '15.00', '卡布奇诺的香味', null, '0', '99', '2019-03-20 22:51:53', '2019-03-20 22:51:56');

API-约定前后台数据交互格式

  请求Get方式 - /product/list

{
    "code":0,
    "msg":"成功",
    "data":[
        {
            "name":"商品目录名称",
            "type":"商品目录类型",
            "product":[
                {
                    "id":"商品id",
                    "name":"商品名称",
                    "price": 100,
                    "description":"商品描述",
                    "icon":"商品图片地址"
                }
            ]
            
        }
    ]
}

  [] 表示数组,可以返回多条

  pom.xml引入依赖

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

  配置文件增加数据库配置

server:
  port: 8080

spring:
  application:
     name: production
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/o2o_cloud?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root
  jpa:
    show-sql: true

eureka:
  client:
    service-url:
       defaultZone: http://localhost:8761/eureka/

  实体类 Product

package com.smart.production.domain;

import lombok.Data;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;

@Data
@Table(name="product")
@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String productId;

    private String productName;
    private Integer productStock;
    private BigDecimal productPrice;
    private String productDescription;
    private String productIcon;
    private Integer productStatus;
    private Integer categoryType;
    private Date createTime;
    private Date updateTime;
}

  Dao层 ProductRepository

  接口, 继承 JpaRepository<T, ID>

 

package com.smart.production.repository;

import com.smart.production.domain.Product;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * JpaRepository<Product, String>  第一个参数为具体的domain对象,第二个参数为主键类型
 */
public interface ProductRepository  extends JpaRepository<Product,String>{
    List<Product> findByProductStatus(Integer productStatus);
}

 

  单元测试

package com.smart.production;

import com.smart.production.domain.Product;
import com.smart.production.domain.ProductCategory;
import com.smart.production.repository.ProductCategoryRepository;
import com.smart.production.repository.ProductRepository;
import org.junit.Assert;
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.Arrays;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductionApplicationTests {

    @Autowired
    ProductRepository productRepository;

    @Test
    public void findByProductStatus(){
        List<Product> productList = productRepository.findByProductStatus(0);
        Assert.assertEquals(3,productList.size());
    }

    @Test
    public void contextLoads() {
    }

}

  实体类 ProductCategory

package com.smart.production.domain;

import lombok.Data;

import javax.persistence.*;
import java.util.Date;

@Data
@Entity
@Table(name="product_category")
public class ProductCategory {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String categoryId;

    private String categoryName;
    private Integer categoryType;
    private Date createTime;
    private Date updateTime;
}

  Dao接口

package com.smart.production.repository;

import com.smart.production.domain.ProductCategory;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

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

  单元测试

package com.smart.production;

import com.smart.production.domain.Product;
import com.smart.production.domain.ProductCategory;
import com.smart.production.repository.ProductCategoryRepository;
import com.smart.production.repository.ProductRepository;
import org.junit.Assert;
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.Arrays;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductionApplicationTests {

    @Autowired
    ProductCategoryRepository productCategoryRepository;

    @Test
    public void findByCategoryType(){
        List<ProductCategory> productCategories = productCategoryRepository.findByCategoryTypeIn(Arrays.asList(07, 98, 99));
        Assert.assertEquals(3,productCategories.size());
    }

    @Test
    public void contextLoads() {
    }

}

  Service层

  ProductService 接口

package com.smart.production.service;

import com.smart.production.domain.Product;

import java.util.List;

public interface ProductService {
    List<Product> getAllUpProduct();
}

  ProductService 接口实现类

package com.smart.production.service;

import com.smart.production.constant.ProductStatus;
import com.smart.production.domain.Product;
import com.smart.production.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductRepository productRepository;

    @Override
    public List<Product> getAllUpProduct() {
        return productRepository.findByProductStatus(ProductStatus.UP.getCode());
    }
}

  ProductStatusEnum

package com.smart.production.constant;

import lombok.Getter;

@Getter
public enum ProductStatus {
    UP(0,"上架"),
    DOWN(1,"下架");

    private int code;
    private String msg;

    ProductStatus(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

  ProductCategoryService 接口

package com.smart.production.service;

import com.smart.production.domain.ProductCategory;
import java.util.List;

public interface ProductCategoryService {

    List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList);

}

  ProductCategoryService 接口实现类

package com.smart.production.service;

import com.smart.production.domain.ProductCategory;
import com.smart.production.repository.ProductCategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductCategoryServiceImpl implements ProductCategoryService {

    @Autowired
    private ProductCategoryRepository productCategoryRepository;

    @Override
    public List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList) {
        return productCategoryRepository.findByCategoryTypeIn(categoryTypeList);
    }
}

  Controller层

  

 

  VO封装

    ResultVO 前后台交互的统一格式模板

package com.smart.production.domain;

import com.smart.production.constant.ErrorCodeMsg;
import lombok.Getter;

@Getter
public class Result<T> {
    private int code;
    private String msg;
    private T data;

    public static <T> Result<T> success(T data){
        return new Result<T>(data);
    }

    public Result(T data) {
        this.code = 0;
        this.msg = "success";
        this.data = data;
    }

    public static <T> Result<T> error(ErrorCodeMsg msgCode){
        return new Result<T>(msgCode);
    }

    public Result(ErrorCodeMsg msgCode){
        if(msgCode==null){
            return ;
        }
        this.code=msgCode.getCode();
        this.msg=msgCode.getMsg();
    }
}

  用到了 ErrorCodeMsg

package com.smart.production.constant;

import lombok.Getter;

@Getter
public enum ErrorCodeMsg {
    serverExcception(1,"服务端异常")
    ;
    private int code;
    private String msg;

    ErrorCodeMsg(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

  ProductVO :返回给前台的商品信息格式,包含目录信息

package com.smart.production.vo;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;

@Data
public class ProductVO {

    // @JsonProperty注解用于属性上,作用是把该属性的名称序列化为另外一个名称,
    // 如把categoryName属性序列化为name
    // 这里约定给前台返回的节点名为name, 但是为了方便理解这个name到底是什么的name,在vo中定义了方便理解的属性名
    @JsonProperty("name")
    private String categoryName;

    @JsonProperty("type")
    private Integer categoryType;

    @JsonProperty("products")
    private List<ProductInfoVO> productInfoVOList;
}

  ProductInfoVO 具体产品的数据VO

package com.smart.production.vo;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.math.BigDecimal;

@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;
}

  ProductController

package com.smart.production.controller;

import com.smart.production.domain.Product;
import com.smart.production.domain.ProductCategory;
import com.smart.production.domain.Result;
import com.smart.production.service.ProductCategoryService;
import com.smart.production.service.ProductService;
import com.smart.production.vo.ProductInfoVO;
import com.smart.production.vo.ProductVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    @Autowired
    private ProductCategoryService categoryService;

    @GetMapping("list")
    public Result list(){
        List<Product> allUpProduct = productService.getAllUpProduct();

        List<Integer> typeList = allUpProduct.stream().map(Product::getCategoryType).collect(Collectors.toList());
        List<ProductCategory> categoryList = categoryService.findByCategoryTypeIn(typeList);

        List<ProductVO> productVOList=new ArrayList<>();
        for(ProductCategory productCategory : categoryList){
            ProductVO productVO = new ProductVO();
            productVO.setCategoryName(productCategory.getCategoryName());
            productVO.setCategoryType(productCategory.getCategoryType());

            List<ProductInfoVO> productInfoVOS=new ArrayList<ProductInfoVO>();
            for(Product product : allUpProduct){
                if(product.getCategoryType().equals(productCategory.getCategoryType())){
                    ProductInfoVO productInfoVO = new ProductInfoVO();
                    BeanUtils.copyProperties(product,productInfoVO);
                    productInfoVOS.add(productInfoVO);
                }
            }
            productVO.setProductInfoVOList(productInfoVOS);
            productVOList.add(productVO);
        }
        return new Result(productVOList);
    }
}  

启动测试

访问 http://localhost:8080/product/list

 

 

posted on 2019-09-21 12:44  溪水静幽  阅读(356)  评论(0)    收藏  举报