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
立志如山 静心求实
浙公网安备 33010602011771号