微信点餐系统(一)买家商品列表

一、开发环境

  • JDK 1.8
  • MySQL 5.7
  • springboot 2.2.4
  • mybatis 1.1.1
  • redis 3.2.8

可能有的人的MySQL版本不到5.7,在下面创建数据库的时候可能会报错。我的解决办法使用Docker创建一个合适版本的MySQL容器,参考:使用docker创建MySQL容器,并在springboot中使用

二、开发工具

  • IDEA
  • Notepad++
  • VirtualBox
  • SQLyog

 三、项目简单分析

该项目的角色主要分为买家端、买家端。买家端主要实现的功能有商品的查询和订单查询、创建、取消等,而卖家端主要是对订单的管理、商品的管理、类目的管理等。

四、在数据库中创建四张数据表

创建一个sell数据库,并在其中创建四张数据表,创建语句如下:

 1 CREATE TABLE product_info(
 2      product_id VARCHAR(32) NOT NULL,
 3      product_name VARCHAR(64) NOT NULL COMMENT "商品名称",
 4      product_price DECIMAL(8,2) NOT NULL COMMENT "单价",
 5      product_stock INT NOT NULL COMMENT "库存",
 6      product_description VARCHAR(64) COMMENT "描述",
 7      product_icon VARCHAR(512) COMMENT "小图",
 8      category_type INT NOT NULL COMMENT "类目编号",
 9      product_status TINYINT(3),
10      create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT "创建时间",
11      update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT "修改时间",
12      PRIMARY KEY(product_id)
13 ) COMMENT "商品表";
14 
15 CREATE TABLE product_category(
16      category_id INT NOT NULL AUTO_INCREMENT,
17      category_name VARCHAR(64) NOT NULL COMMENT '类目名称',
18      category_type INT NOT NULL COMMENT '类目编号',
19      create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
20      update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
21      PRIMARY KEY (category_id),
22      UNIQUE KEY uqe_category_type (category_type)
23 ) COMMENT '类目表';
24 
25 CREATE TABLE order_master (
26      order_id VARCHAR(32) NOT NULL,
27      buyer_name VARCHAR(32) NOT NULL COMMENT '买家名字',
28      buyer_phone VARCHAR(32) NOT NULL COMMENT '买家电话',
29      buyer_address VARCHAR(128) NOT NULL COMMENT '买家地址',
30      buyer_openid VARCHAR(64) NOT NULL COMMENT '买家微信openid',
31      order_amount DECIMAL(8,2) NOT NULL COMMENT '订单总金额',
32      order_status TINYINT(3) NOT NULL DEFAULT 0 COMMENT '订单状态,默认0新下单',
33      pay_status TINYINT(3) NOT NULL DEFAULT 0 COMMENT '支付状态,默认0未支付',
34      create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
35      update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
36      PRIMARY KEY (order_id),
37      KEY idx_buyer_openid (buyer_openid)
38 ) COMMENT '订单表';
39 
40 CREATE TABLE order_detail (
41      detail_id VARCHAR(32) NOT NULL,
42      order_id VARCHAR(32) NOT NULL,
43      product_id VARCHAR(32) NOT NULL,
44      product_name VARCHAR(64) NOT NULL COMMENT '商品名称',
45      product_price DECIMAL(8,2) NOT NULL COMMENT '商品价格',
46      product_quantity INT NOT NULL COMMENT '商品数量',
47      product_icon VARCHAR(512) COMMENT '商品小图',
48      create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
49      update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
50      PRIMARY KEY (detail_id),
51      KEY idx_order_id (order_id)
52 ) COMMENT '订单详情表';
View Code

还差一张买家信息表,但是暂时还用不到就没创建。本文主要是买家商品list的实现就先介绍其中两张,product_category是商品的类目表,product_info是商品信息表。

 五.根据API文档在vo包下创建需要返回数据的类

商品列表的API文档如下:

 1 ###商品列表
 2 
 3 ```
 4 GET /sell/buyer/product/list
 5 ```
 6 
 7 参数
 8 
 9 ```
10 11 ```
12 
13 返回
14 
15 ```
16 {
17     "code": 0,
18     "msg": "成功",
19     "data": [
20         {
21             "name": "热榜",
22             "type": 1,
23             "foods": [
24                 {
25                     "id": "123456",
26                     "name": "皮蛋粥",
27                     "price": 1.2,
28                     "description": "好吃的皮蛋粥",
29                     "icon": "http://xxx.com",
30                 }
31             ]
32         },
33         {
34             "name": "好吃的",
35             "type": 2,
36             "foods": [
37                 {
38                     "id": "123457",
39                     "name": "慕斯蛋糕",
40                     "price": 10.9,
41                     "description": "美味爽口",
42                     "icon": "http://xxx.com",
43                 }
44             ]
45         }
46     ]
47 }
48 ```

根据商品列表文档可知需要返回数据最外层有"code","msg","data"字段,由于各个API"data"内内容不一致,将"data"类型指定为泛型T

因此创建一个ResultVO类

 1 package club.nipengfei.VO;
 2 
 3 import lombok.Data;
 4 
 5 @Data
 6 public class ResultVO<T> {
 7 
 8     /** 错误码 */
 9     private Integer code;
10 
11     /** 提示信息 */
12     private String msg;
13 
14     /** 具体内容 */
15     private T data;
16 
17 }

根据上述的文档可知"data"内是一个列表,其中一个元素的"name"表示"category_name","type"表示"category_type","foods"表示商品信息列表。

根据这些字段在vo包下创建一个ProductVO类。@Data注解:lombok插件的一个注解自动生成get,set等方法。@JsonProperty注解:可以让返回前端例如"categoryName"变成"name",如果字段直接使用"name"不能方便获取该字段含义。

 1 package club.nipengfei.VO;
 2 
 3 import com.fasterxml.jackson.annotation.JsonProperty;
 4 import lombok.Data;
 5 
 6 import java.util.List;
 7 
 8 /**
 9  * 商品(包含类目)
10  */
11 @Data
12 public class ProductVO {
13 
14     @JsonProperty("name")
15     private String categoryName;
16 
17     @JsonProperty("type")
18     private Integer categoryType;
19 
20     @JsonProperty("foods")
21     private List<ProductInfoVO> productInfoVOList;
22 
23 }

"foods"列表中表示属于该类目"category"的商品,使用ProductInfoVO类封装。类型BigDecimal对应数据表中的"DECIMAL"一般钱都用这个类型。

 1 package club.nipengfei.VO;
 2 
 3 import com.fasterxml.jackson.annotation.JsonProperty;
 4 import lombok.Data;
 5 
 6 import java.math.BigDecimal;
 7 
 8 /**
 9  * 商品详情
10  */
11 @Data
12 public class ProductInfoVO {
13 
14     @JsonProperty("id")
15     private String productId;
16 
17     @JsonProperty("name")
18     private String productName;
19 
20     @JsonProperty("price")
21     private BigDecimal productPrice;
22 
23     @JsonProperty("description")
24     private String productDescription;
25 
26     @JsonProperty("icon")
27     private String productIcon;
28 }

六、开发repository层(dao层)

在这之前需要根据数据库中的数据表建立相应映射类,ProductCategory类、ProductInfo类。

 1 package club.nipengfei.dataobject;
 2 
 3 import lombok.Data;
 4 
 5 import java.util.Date;
 6 
 7 /**
 8  * 类目
 9  */
10 @Data
11 public class ProductCategory {
12 
13     /**
14      * 类目id
15      */
16     private Integer category_id;
17 
18     /**
19      * 类目名字
20      */
21     private String category_name;
22 
23     /**
24      * 类目编号
25      */
26     private Integer category_type;
27 
28     private Date create_time;
29 
30     private Date update_time;
31 
32 }
View Code
 1 package club.nipengfei.dataobject;
 2 
 3 import lombok.Data;
 4 
 5 import java.math.BigDecimal;
 6 
 7 @Data
 8 public class ProductInfo {
 9 
10     private String product_id;
11 
12     private String product_name;
13 
14     private BigDecimal product_price;
15 
16     private Integer product_stock;
17 
18     private String product_description;
19 
20     private String product_icon;
21 
22     /** 状态,0正常 1下架*/
23     private Integer product_status;
24 
25     /** 类目编号*/
26     private Integer category_type;
27 }
View Code

在pom文件中引入相应依赖

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
View Code

并在配置文件中配置数据库的信息

1 spring.datasource.url=jdbc:mysql://192.168.1.199/sell?characterEncoding=utf-8&useSSL=FALSE
2 spring.datasource.username=root
3 spring.datasource.password=123456
View Code

 在ProductInfoRepository接口内写一个findUpAll抽象方法,将product_info表中上架的商品全部查出来,放入List<ProductInfo>中。然后在ProductCategoryRepository接口中写一个findByCategoryTypeIn抽象方法,根据List<Integer>参数查询出List<ProductCategory>。

@Mapper注解会将注解的接口交给Mybatis处理,如果觉得麻烦可以在启动类上加上@MapperScan("club.nipengfei.repository")代替,该注解可以自动扫描repository包下的类

@Repository注解将其交给spring处理,自动注册为spring bean

 1 package club.nipengfei.repository;
 2 
 3 import club.nipengfei.dataobject.ProductInfo;
 4 import com.github.pagehelper.Page;
 5 import org.apache.ibatis.annotations.Insert;
 6 import org.apache.ibatis.annotations.Mapper;
 7 import org.apache.ibatis.annotations.Select;
 8 import org.apache.ibatis.annotations.Update;
 9 import org.springframework.stereotype.Repository;
10 
11 import java.util.List;
12 
13 @Repository
14 @Mapper
15 public interface ProductInfoRepository {
16 
17     @Select("select * from product_info where product_status=0")
18     List<ProductInfo> findUpAll();
19 
20 }

下面的select语句中使用了mybatis的动态SQL,参考:https://mybatis.org/mybatis-3/zh/dynamic-sql.html

注意在注解中使用动态SQL需要使用<script>

 1 package club.nipengfei.repository;
 2 
 3 import club.nipengfei.dataobject.ProductCategory;
 4 import org.apache.ibatis.annotations.Insert;
 5 import org.apache.ibatis.annotations.Mapper;
 6 import org.apache.ibatis.annotations.Param;
 7 import org.apache.ibatis.annotations.Select;
 8 import org.springframework.stereotype.Repository;
 9 
10 import java.util.List;
11 
12 @Mapper
13 @Repository
14 public interface ProductCategoryRepository {
15 
16 
17     @Select("<script>select * from product_category " +
18             "<where>" +
19             "<if test='list != null and list.size()>0' >"+
20             "<foreach collection='list' open='and category_type in (' close=')' item='id' separator=','> #{id}</foreach>"+
21             "</if>"+
22             "</where>"+
23             "</script>")
24     List<ProductCategory> findByCategoryTypeIn(@Param("list") List<Integer> list);
25 }

七、service层开发

@Service注解与上面的@Repository一样将其注册为spring bean

@Autowired注解,bean的自动注入

 1 package club.nipengfei.service;
 2 
 3 import club.nipengfei.dataobject.ProductInfo;
 4 import club.nipengfei.dto.CartDTO;
 5 import com.github.pagehelper.Page;
 6 
 7 import java.util.List;
 8 
 9 public interface ProductService {
10 
11     /**
12      * 查询所有在架商品列表
13      * @return
14      */
15     List<ProductInfo> findUpAll();
16 
17 }
View Code
 1 package club.nipengfei.service.impl;
 2 
 3 import club.nipengfei.dataobject.ProductInfo;
 4 import club.nipengfei.dto.CartDTO;
 5 import club.nipengfei.enums.ResultEnum;
 6 import club.nipengfei.exception.SellException;
 7 import club.nipengfei.repository.ProductInfoRepository;
 8 import club.nipengfei.service.ProductService;
 9 import com.github.pagehelper.Page;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.stereotype.Service;
12 import org.springframework.transaction.annotation.Transactional;
13 
14 import java.util.List;
15 
16 @Service
17 public class ProductServiceImpl implements ProductService {
18 
19     @Autowired
20     private ProductInfoRepository repository;
21 
22     @Override
23     public List<ProductInfo> findUpAll() {
24         return repository.findUpAll();
25     }
26 
27 }
View Code
 1 package club.nipengfei.service;
 2 
 3 import club.nipengfei.dataobject.ProductCategory;
 4 
 5 import java.util.List;
 6 
 7 public interface CategoryService {
 8 
 9     List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList);
10 
11 }
View Code
 1 package club.nipengfei.service.impl;
 2 
 3 import club.nipengfei.dataobject.ProductCategory;
 4 import club.nipengfei.repository.ProductCategoryRepository;
 5 import club.nipengfei.service.CategoryService;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.stereotype.Service;
 8 
 9 import java.util.List;
10 
11 @Service
12 public class CategoryServiceImpl implements CategoryService {
13 
14     @Autowired
15     private ProductCategoryRepository repository;
16 
17     @Override
18     public List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList) {
19         return repository.findByCategoryTypeIn(categoryTypeList);
20     }
21 
22 }
View Code

八、controller层的开发

根据API文档请求方法和路径,在配置文件中写入一个项目路径"/sell",新建一个BuyerProductController类在这上面加上注解@RequestMapping指定值为"/buyer/product",在list方法上使用@GetMapping注解,指定值为"list"。@RestController注解@ResponseBody和@Controller的组合注解,@ResponseBody注解是返回json,@Controller注解处理http请求。

1 server.servlet.context-path=/sell
 1 package club.nipengfei.controller;
 2 
 3 import club.nipengfei.VO.ProductInfoVO;
 4 import club.nipengfei.VO.ProductVO;
 5 import club.nipengfei.VO.ResultVO;
 6 import club.nipengfei.dataobject.ProductCategory;
 7 import club.nipengfei.dataobject.ProductInfo;
 8 import club.nipengfei.service.CategoryService;
 9 import club.nipengfei.service.ProductService;
10 import club.nipengfei.utils.ResultVOUtil;
11 import org.springframework.beans.BeanUtils;
12 import org.springframework.beans.factory.annotation.Autowired;
13 import org.springframework.web.bind.annotation.GetMapping;
14 import org.springframework.web.bind.annotation.RequestMapping;
15 import org.springframework.web.bind.annotation.RestController;
16 
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.List;
20 
21 @RestController
22 @RequestMapping("/buyer/product")
23 public class BuyerProductController {
24 
25     @Autowired
26     private ProductService productService;
27 
28     @Autowired
29     private CategoryService categoryService;
30 
31 
32     @GetMapping("/list")
33     public ResultVO list() {
34 
35         // 1.查询所有上架商品
36         List<ProductInfo> productInfoList = productService.findUpAll();
37 
38         // 2.查询类目(一次查询)
39         List<Integer> categoryTypeList = new ArrayList<>();
40         for (ProductInfo productInfo : productInfoList) {
41             categoryTypeList.add(productInfo.getCategory_type());
42         }
43         /** 当categoryTypeList为空时,即商品都没有上架,程序会报错 */
44         List<ProductCategory> productCategoryList = categoryService.findByCategoryTypeIn( categoryTypeList);
45 
46         // 3.数据拼接
47         List<ProductVO> productVOList = new ArrayList<>();
48         for (ProductCategory productCategory : productCategoryList) {
49             ProductVO productVO = new ProductVO();
50             productVO.setCategoryType(productCategory.getCategory_type());
51             productVO.setCategoryName(productCategory.getCategory_name());
52 
53             List<ProductInfoVO> productInfoVOList = new ArrayList<>();
54             for (ProductInfo productInfo : productInfoList) {
55                 if (productInfo.getCategory_type().equals(productCategory.getCategory_type())){
56                     ProductInfoVO productInfoVO = new ProductInfoVO();
57 
58                     // BeanUtils.copyProperties(productInfo,productInfoVO);
59                     // 由于我的productInfo和productInfoVO的字段名不一致,不能使用上面的工具,而使用下面的
60                     productInfoVO.setProductId(productInfo.getProduct_id());
61                     productInfoVO.setProductName(productInfo.getProduct_name());
62                     productInfoVO.setProductPrice(productInfo.getProduct_price());
63                     productInfoVO.setProductDescription(productInfo.getProduct_description());
64                     productInfoVO.setProductIcon(productInfo.getProduct_icon());
65 
66                     productInfoVOList.add(productInfoVO);
67                 }
68             }
69             productVO.setProductInfoVOList(productInfoVOList);
70             productVOList.add(productVO);
71         }
72 
73         return ResultVOUtil.success(productVOList);
74     }
75 }
View Code
 1 package club.nipengfei.utils;
 2 
 3 import club.nipengfei.VO.ResultVO;
 4 
 5 public class ResultVOUtil {
 6 
 7     public static ResultVO success(Object object){
 8         ResultVO resultVO = new ResultVO();
 9         resultVO.setData(object);
10         resultVO.setCode(0);
11         resultVO.setMsg("成功");
12         return resultVO;
13     }
14 
15     public static ResultVO success(){
16         return success(null);
17     }
18 
19     public static ResultVO error(Integer code,String msg){
20         ResultVO resultVO = new ResultVO();
21         resultVO.setCode(code);
22         resultVO.setMsg(msg);
23         return resultVO;
24     }
25 }
View Code

在本地浏览器或者Postman中输入http://127.0.0.1:8080/sell/buyer/product/list,就可以发现返回json格式与API文档一致

 九、存在的问题

@Mapper,@Repository,@Autowired,@RestController等注解具体是怎么工作的还是不太了解。mybatis中动态sql使用有点困难。

posted @ 2020-03-06 15:02  轻舟万里  阅读(373)  评论(0编辑  收藏  举报