up:: SpringBoot电商项目商品模块介绍

说明:

(1) 本篇博客内容:后台的【增加商品】接口;

(2) 本篇博客需要注意的点:

● 需要注意:【增加商品】接口:本篇博客还没有完全开发完;这是因为图片的地址,还无法上传;

有关,上传图片的内容,在后面几篇博客介绍;

● 新增商品的时候,也要防止商品名称重名;


一:【增加商品】接口介绍;

该接口是后台系统的;

(1)【增加商品】接口文档;

(2)【增加商品】接口:在界面上的效果;

(3)【增加商品】接口:和【上传图片】接口的关系;

因为增加商品时候,需要附带上传商品图片;所以,就【增加商品】接口来说,其中的image属性,就是我们【把图片上传到服务器后的,图片的地址】;

而,这个地址,是只要把图片上传到服务器后,才能得到的;

所以,我们在开发【增加商品】接口时,也要开发【上传图片】接口;

【上传图片】接口会把图片上传到服务器,并返回图片在服务器上的地址;然后我们在把这个地址拿过来,作为【增加商品】接口的image参数;


二:正式开发;

1.创建ProductAdminController类;创建增加商品的方法:addProduct()方法;

ProductAdminController类:

 
     package com.imooc.mall.controller;
 
     import com.imooc.mall.common.ApiRestResponse;
     import com.imooc.mall.model.request.AddProductReq;
     import com.imooc.mall.service.ProductService;
     import io.swagger.annotations.ApiOperation;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.stereotype.Controller;
     import org.springframework.web.bind.annotation.PostMapping;
     import org.springframework.web.bind.annotation.RequestBody;
     import org.springframework.web.bind.annotation.ResponseBody;
 
     import javax.validation.Valid;
 
     /**
      * 描述:【商品模块】后台的Controller
      */
     @Controller
     public class ProductAdminController {
 
         @Autowired
         ProductService productService;
 
         @ApiOperation("新增商品")
         @PostMapping("/admin/product/add")
         @ResponseBody
         public ApiRestResponse addProduct(@Valid @RequestBody AddProductReq addProductReq) {
             productService.add(addProductReq);
             return ApiRestResponse.success();
         }
     }
 

说明:

(1)【url、请求方式:要符合接口规范】,【Swagger文档,添加接口说明】,【返回值要序列化为JSON】;


(2)因为接口参数很多,所以我们额外创建【AddProductRequest】这个bean去接收参数;同时,因为这儿需要参数校验,所以我们使用了Validation参数校验(@Valid);

AddProductReq类:

 
     package com.imooc.mall.model.request;
 
     import javax.validation.constraints.Max;
     import javax.validation.constraints.Min;
     import javax.validation.constraints.NotNull;
     import java.util.Date;
 
     public class AddProductReq {
 
         @NotNull(message = "商品名称不能为null")
         private String name;
 
         @NotNull(message = "商品图片不能为null")
         private String image;
 
         private String detail;
 
         @NotNull(message = "商品分类不能为null")
         private Integer categoryId;
 
         @NotNull(message = "商品价格不能为null")
         @Min(value = 1, message = "价格不能小于1")
         private Integer price;
 
         @NotNull(message = "商品库存不能为null")
         @Max(value = 10000, message = "库存不能大于10000")
         private Integer stock;
 
         private Integer status;
 
         public String getName() {
             return name;
         }
 
         public void setName(String name) {
             this.name = name;
         }
 
         public String getImage() {
             return image;
         }
 
         public void setImage(String image) {
             this.image = image;
         }
 
         public String getDetail() {
             return detail;
         }
 
         public void setDetail(String detail) {
             this.detail = detail;
         }
 
         public Integer getCategoryId() {
             return categoryId;
         }
 
         public void setCategoryId(Integer categoryId) {
             this.categoryId = categoryId;
         }
 
         public Integer getPrice() {
             return price;
         }
 
         public void setPrice(Integer price) {
             this.price = price;
         }
 
         public Integer getStock() {
             return stock;
         }
 
         public void setStock(Integer stock) {
             this.stock = stock;
         }
 
         public Integer getStatus() {
             return status;
         }
 
         public void setStatus(Integer status) {
             this.status = status;
         }
     }

首先,这个类就是用来接收前端传过来的参数的;所以,这个类要比照接口的参数来写;

然后,这儿校验规则:

● 我们即参考了实际的业务需求:比如image;虽然在数据库中这个对应的字段,我们要求不能为null,但是我们是设有默认值的;所以,纯技术来说,这个接口的image参数可以不传;但是,从业务的角度来说,我们又要求用户传image;所以,我们的image也要求不为空了;

● 又比如status,虽然数据库要求是非空,但其设置了默认值;所以,综合业务角度来说,可以不传status,如果不传,我们就使用默认值1就行了;

● 又比如,我们要求price不能低于1分,stock库存不能超过10000;否则就给出对应的提示信息;


(3)因为要用到Validation参数校验,所以,需要使用@Valid注解;;因为这儿是POST请求,而且参数是放在Body中的,所以需要使用@RequestBody注解;


(4)有关Service层的listCategoryForCustomer()方法,在下一部分介绍;


(5)【新增商品】接口,其实还没开发完;完整的增加商品,需要上传图片,而这就涉及到了后面要介绍的【上传图片】接口;

2.创建ProductService接口和ProductServiceImpl实现类;在ProductServiceImpl实现类中,编写新增商品的方法add();然后在ProductService接口中,反向生成方法的声明;

(1)在ProductServiceImpl实现类中,编写新增商品的方法add();

 
     package com.imooc.mall.service.impl;
 
     import com.imooc.mall.exception.ImoocMallException;
     import com.imooc.mall.exception.ImoocMallExceptionEnum;
     import com.imooc.mall.model.dao.ProductMapper;
     import com.imooc.mall.model.pojo.Product;
     import com.imooc.mall.model.request.AddProductReq;
     import com.imooc.mall.service.ProductService;
     import org.springframework.beans.BeanUtils;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.stereotype.Service;
 
     /**
      * 描述:商品Service实现类;
      */
     @Service
     public class ProductServiceImpl implements ProductService {
 
         @Autowired
         ProductMapper productMapper;
 
         /**
          * 新增商品
          * @param addProductReq
          */
         @Override
         public void add(AddProductReq addProductReq) {
             //因为,我们是通过Product这个类,和数据库打交道的;
             //所以,我们把addProductReq的内容,复制成一个product;
             Product product = new Product();
             BeanUtils.copyProperties(addProductReq, product);
 
             //首先,我们要看下,商品时候重名
             Product productOld = productMapper.selectByName(product.getName());
             //如果查出来了,表示数据库中已经有叫这个名字的商品了;那么我们就抛出一个名字已存在的异常
             if (productOld != null) {
                 throw new ImoocMallException(ImoocMallExceptionEnum.NAME_EXISTED);
             }
             //如果上面没问题,就去调用方法,向数据库中插入数据;
             int count = productMapper.insertSelective(product);
             //如果count=0,表示插入失败了;我们就抛出一个新增失败的异常;
             if (count == 0) {
                 throw new  ImoocMallException(ImoocMallExceptionEnum.CREATE_FAILED);
             }
         }
     }
 

说明:

(1) 看注释;

(2) 其中,在看商品是否重名的时候,我们在Mapper中创建了一个根据name查商品的方法;有关这个方法在下一部分介绍;

(3) 其中用到的insertSelective()方法,是我们前面利用【mybatis-generator】插件生成的;


(2)然后在ProductService接口中,反向生成方法的声明;

3.在ProductMapper接口中,定义【根据】name查询商品】的方法selectByName();然后在ProductMapper.xml中编写方法的SQL;

(1)在ProductMapper接口中,定义【根据】name查询商品】的方法selectByName();


(2)然后在ProductMapper.xml中编写方法的SQL;

  <select id="selectByName" parameterType="java.lang.String" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List"/>
    from imooc_mall_product
    where name = #{name,jdbcType=VARCHAR}
  </select>

三:启动项目,测试【增加商品】接口;

启动项目;

然后,这儿仅仅出于出于测试【增加商品】接口;这儿先不涉及后面的【上传文件】,所以为了省事,不用自己写JSON,我们可以直接复制接口文档中的内容;(PS:等到后面开发了【上传图片】接口后,这个image属性需要是,【上传图片】接口返回给前端的那个地址;这儿,我们仅仅演示【增加商品】接口,所以这儿我们就暂时伪造了一个实际上不存在的image属性)