up:: SpringBoot电商项目商品模块商品接口之图片

说明:

(1) 本篇博客内容:开发【更新商品】接口;

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

● 【更新商品】时的时候,要编写对应的逻辑,以确保此次更新的结果不会导致商品名重名;


一:【更新商品】接口介绍;

(1)【更新商品】接口文档;

这个接口是需要管理员用户登录的,而我们在AdminFilterConfig中,也对其进行了统一的处理;

(2)更新商品,在页面上的表现;

(3)一个疑问?:【增加商品】接口和【更新商品】接口,这么像,为什么不统一写成一个接口?

二者的接口文档:请求方式一样、参数差不多(更新接口多了一个商品id)、参数都在POST请求的Body中、返回内容等,都差不多;

那么,为什么不建议把这两个接口开发成一个?这是因为:

● 这两个接口虽然很像,但二者是不同的;【新增商品】和【更新商品】这两个业务,现在看起来功能都差不多;但是,后面随着业务的发展,【新增商品】和【更新商品】这两个业务,会有更多不彼此同的功能;所以,如果把【新增商品】接口和【更新商品】接口合并的话,后期就不利于维护;

● 比如下面这个例子:

【新增商品】的时候,需要新增创建人这一个字段;而【更新商品】的时候,不允许更新创建人这个字段;通过这例子,能够感受到,以后随着业务的发展,【新增商品】和【更新商品】这两个业务,会有更多彼此同的功能;而如果强行把两个接口合并的话,后期维护就会比较困难;


二:正式开发;

1.在ProductAdminController类中,创建更新商品的方法:updateProduct()方法;

 
         /**
          * 更新商品
          * @param updateProductReq
          * @return
          */
         @ApiOperation("更新商品")
         @PostMapping("/admin/product/update")
         @ResponseBody
         public ApiRestResponse updateProduct(@Valid @RequestBody UpdateProductReq updateProductReq) {
             Product product = new Product();
             BeanUtils.copyProperties(updateProductReq, product);
             productService.update(product);
             return ApiRestResponse.success();
         }

说明:

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

UpdateProductReq:

 
     package com.imooc.mall.model.request;
 
     import javax.validation.constraints.Max;
     import javax.validation.constraints.Min;
     import javax.validation.constraints.NotNull;
 
     public class UpdateProductReq {
         @NotNull(message = "商品id不能为null")
         private Integer id;
 
     //    @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 Integer getId() {
             return id;
         }
 
         public void setId(Integer id) {
             this.id = id;
         }
 
         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;
         }
     }

● 因为更新接口的参数中,有商品id,所以这个类中也添加了id属性;而且,要求id这个参数是必必须传的,所以我们也使用了Validation的非空校验;

● 而究竟传那些参数、没有传那些参数,是由前端决定的;反正,后端的要求是:必须要传id,其他参数随便;


(2)方法的简单说明;


(3)service层的更新商品的update()方法,在下一部分介绍;

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

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

         /**
          * 更新商品
          * @param product
          */
         @Override
         public void update(Product product) {
             //先根据商品名,去数据库中查,看是否有叫这个名字的商品数据
             Product productOld = productMapper.selectByName(product.getName());
             //如果上面查到了
             //而且【上面查到的商品的id】和【我们前台穿过来的商品id不一样】,那么不允许更新,抛出不允许重名异常;
             // 很显然,这一条也是为了防止商品名重名;
             if (productOld != null && productOld.getId() != product.getId())
						 {
                 throw new  ImoocMallException(ImoocMallExceptionEnum.NAME_EXISTED);
             }
             //然后调用Dao层的更新方法,去更新数据
             int count = productMapper.updateByPrimaryKeySelective(product);
             //如果更新失败,就抛出更新失败异常;
             if (count == 0) {
                 throw new  ImoocMallException(ImoocMallExceptionEnum.UPDATE_FAILED);
             }
         }

说明:

(1) 更新商品的时候,也要防止【我们填写的更新信息】可能会导致商品名重名的情况;

(2) 确认不会重名后,就调用【我们通过mybatis-generator插件生成的,updateByPrimaryKeySelective()方法】去更新数据;至于为什么要使用这个方法,是因为:更新的时候,前端传的数据可能不全,这就导致Product对象可能很多属性没有值,所以用updateByPrimaryKeySelective这个方法,是合适的;


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


三:测试【更新商品】接口;

比照【更新商品】接口对数据的要求和格式,然后根据id=46的那条数据,来组织数据;

先调用【管理员登录】接口,然后调用【更新商品】接口;