2022-05-27  2022-05-27    16847 字   34 分钟

第四章

规格管理、模板管理、分类管理以及商品发布

优就业.JAVA教研室

学习目标

目标一:规格管理

目标二:模板管理

目标三:商品分类管理

目标四:了解电商概念SPU 和SKU

目标五:新增商品、修改商品

目标六:删除商品

目标七:审核商品

目标八:注解式事务

一 代码生成器

1 代码生成

我们接下来使用《优就业JAVA代码生成器1.0》来完成代码的编写。生成后将代码拷贝到工程中。具体步骤如下:

(1)导入(资源\配套软件\dongyimaiMakeCode)代码生成器工程到开发工具。

(2)修改数据库连接配置:打开src/main/resources/properties/db.properties

#pojo实体类所在包
pojoPackage=com.offcn.sellergoods.pojo
#Dao接口所在包
mapperPackage=com.offcn.sellergoods.dao
#service服务接口所在包
serviceInterfacePackage=com.offcn.sellergoods.service
#service服务实现类所在包
serviceInterfaceImplPackage=com.offcn.sellergoods.service.impl
#controller控制器所在包
controllerPackage=com.offcn.sellergoods.controller
#feignFeign调用接口所在包
feignPackage=com.offcn.sellergoods.feign
#是否开启swagger注解
enableSwagger=true
#swagger-ui所在目录
swaggeruipath=com.offcn.swagger
#服务名,提供feign调用
serviceName=sellergoods

#数据库地址、账号密码
url=jdbc:mysql://192.168.188.1:3306/dongyimai-db
uname=root
pwd=root
driver=com.mysql.jdbc.Driver

(3)运行代码生成主程序:CodeApplication及可生成代码。

(4)提示成功后,到生成路径去找生成的代码,并拷贝到我们的工程中。

PojoDaoServiceServiceImplController都生成到了 /src/main/java目录下

2 代码拷贝

将商品相关代码拷贝到工程

(1)拷贝实体类

(2)拷贝Dao层接口

(3)拷贝服务接口

(4)拷贝服务实现类

(5)拷贝控制器

二 Swagger2的使用

1 配置Swagger文档

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。Swagger 让部署管理和使用功能强大的API从未如此简单。

1) 在dongyimai-parent工程中pom.xml引入Swagger2和swagger ui

<!-- springfox-swagger2 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<!-- springfox-swagger-ui -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

2) 在模块中编写配置类(@EnableSwagger2 开启swagger2自动生成api文档功能)

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    //配置文档属性
    private ApiInfo getApiInfo(){
      return   new ApiInfoBuilder().title("商品微服务接口文档")
                .description("给前端妹子看的")
                .version("1.0")
                .termsOfServiceUrl("http://www.ujiuye.com")
                .build();
    }

    //创建文档配置对象
    @Bean
    public Docket docket(){
      return   new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo())
                .groupName("group1")
                .select()
                .build();
    }
}

3)访问文档

http://localhost:9001/swagger-ui.html

试着操作一下品牌管理的内容~

三 规格管理

1 需求分析

规格管理是用于管理规格选项的单元。规格是例如颜色、手机运行内存等信息,选项是例如系统:安卓(Android)后置摄像头像素:2000万及以上 热点:快速充电等信息 。

前端交互方式见管理后台的静态原型

2 表结构分析

tb_specification 规格表

字段 类型 长度 含义
id Bigint 主键
spec_name Varchar 255 规格名称

tb_specification_option 规格选项表

字段 类型 长度 含义
id Bigint 主键
option_name Varchar 200 规格选项名称
spec_id Bigint 30 规格ID
orders Int 11 排序

3 代码实现

3.1 新增规格

实现思路:我们将规格和规格选项数据合并成一个对象来传递,这时我们需要用一个对象将这两个对象组合起来。在业务逻辑中,得到组合对象中的规格和规格选项列表,插入规格返回规格ID,然后循环插入规格选项。

(1)在dongyimai-sellergoods-service-api 建立com.offcn.sellergoods.group包,包下建立SpecEntity类

@ApiModel(description = "规格复合实体类",value = "SpecEntity")
public class SpecEntity implements Serializable {
    @ApiModelProperty(value = "规格对象",required = false)
    private Specification specification;
    @ApiModelProperty(value = "规格选项对象",required = false)
    private List<SpecificationOption> specificationOptionList;

    public Specification getSpecification() {
        return specification;
    }

    public void setSpecification(Specification specification) {
        this.specification = specification;
    }

    public List<SpecificationOption> getSpecificationOptionList() {
        return specificationOptionList;
    }

    public void setSpecificationOptionList(List<SpecificationOption> specificationOptionList) {
        this.specificationOptionList = specificationOptionList;
    }
}

(2)业务层

修改com.offcn.sellergoods.service.SpecificationService,新增方法

/***
* 新增Specification
* @param specEntity
*/
void add(SpecEntity specEntity);

修改com.offcn.sellergoods.service.impl.SpecificationServiceImpl,新增增加规格方法代码如下:

/**
     * 增加Specification
     * @param specEntity
     */
    @Override
    public void add(SpecEntity specEntity){
        //1.保存规格名称
        this.save(specEntity.getSpecification());
        //2.得到规格名称ID
        if (null != specEntity.getSpecificationOptionList() && specEntity.getSpecificationOptionList().size() > 0) {
            for (SpecificationOption specificationOption : specEntity.getSpecificationOptionList()) {
                //3.向规格选项中设置规格ID
                specificationOption.setSpecId(specEntity.getSpecification().getId());
                //4.保存规格选项
                specificationOptionMapper.insert(specificationOption);
            }
        }
    }

(3)控制层

修改SpecificationController新增方法

    /***
     * 新增Specification数据
     * @param specEntity
     * @return
     */
    @ApiOperation(value = "Specification添加",notes = "添加Specification方法详情",tags = {"SpecificationController"})
    @PostMapping
    public Result add(@RequestBody  @ApiParam(name = "SpecEntity复合实体",value = "传入JSON数据",required = true) SpecEntity specEntity){
        //调用SpecificationService实现添加Specification
        specificationService.add(specEntity);
        return new Result(true,StatusCode.OK,"添加成功");
    }

测试数据

{
	"specification": {
		"specName": "测试规格01"
	},
	"specificationOptionList": [
		{
			"optionName": "16G",
			"orders": "1"
		},
		{
			"optionName": "21G",
			"orders": "2"
		},
		{
			"optionName": "33G",
			"orders": "3"
		}
	]
}

3.2 根据ID查询规格

(1)业务层

修改com.offcn.sellergoods.service.SpecificationService,查询规格方法,代码如下:

SpecEntity findById(Long id);

(2)修改com.offcn.sellergoods.service.impl.SpecificationServiceImpl,查询规格方法,代码如下:

public SpecEntity findById(Long id) {
    Specification specification = specificationMapper.selectById(id);
    QueryWrapper<SpecificationOption> queryWrapper = new QueryWrapper();
    queryWrapper.eq("spec_id",id);
    List<SpecificationOption> specificationOptionList =  specificationOptionMapper.selectList(queryWrapper);
    SpecEntity specEntity = new SpecEntity();
    specEntity.setSpecification(specification);
    specEntity.setSpecificationOptionList(specificationOptionList);
    return specEntity;
}

(3)控制层

SpecificationController修改方法

@ApiOperation(value = "Specification根据ID查询",notes = "根据ID查询Specification方法详情",tags = {"SpecificationController"})
@ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
@GetMapping("/{id}")
public Result<SpecEntity> findById(@PathVariable Long id){
    //调用SpecificationService实现根据主键查询Specification
    SpecEntity specification = specificationService.findById(id);
    return new Result<SpecEntity>(true,StatusCode.OK,"查询成功",specification);
}

3.3 修改规格

(1)业务层

修改com.offcn.sellergoods.service.SpecificationService,修改规格方法,代码如下:

    /***
     * 修改Specification数据
     * @param specEntity
     */
    void update(SpecEntity specEntity);

修改com.offcn.sellergoods.service.impl.SpecificationServiceImpl,修改品牌方法,代码如下:

    /**
     * 修改Specification
     * @param specEntity
     */
    @Override
    public void update(SpecEntity specEntity){
        //1.修改规格名称对象
        this.updateById(specEntity.getSpecification());
        //2.根据ID删除规格选项集合
        QueryWrapper<SpecificationOption> queryWrapper = new QueryWrapper<SpecificationOption>();
        queryWrapper.eq("spec_id", specEntity.getSpecification().getId());
        //执行删除
        specificationOptionMapper.delete(queryWrapper);
        //3.重新插入规格选项
        if (!CollectionUtils.isEmpty(specEntity.getSpecificationOptionList())) {
            for (SpecificationOption specificationOption : specEntity.getSpecificationOptionList()) {
                //先设置规格名称的ID
                specificationOption.setSpecId(specEntity.getSpecification().getId());
                specificationOptionMapper.insert(specificationOption);
            }
        }
    }

(2)控制层

SpecificationController修改方法

    /***
     * 修改Specification数据
     * @param specEntity
     * @param id
     * @return
     */
    @ApiOperation(value = "Specification根据ID修改",notes = "根据ID修改Specification方法详情",tags = {"SpecificationController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
    @PutMapping(value="/{id}")
    public Result update(@RequestBody @ApiParam(name = "Specification对象",value = "传入JSON数据",required = false) SpecEntity specEntity,@PathVariable Long id){
        //设置主键值
        specEntity.getSpecification().setId(id);
        specificationService.update(specEntity);
        return new Result(true,StatusCode.OK,"修改成功");
    }

测试数据

{
	"specification": {
		"specName": "测试规格01_update"
	},
	"specificationOptionList": [
		{
			"optionName": "21G_update",
			"orders": "2"
		},
		{
			"optionName": "33G",
			"orders": "3"
		},
		{
			"optionName": "48G",
			"orders": "4"
		}
	]
}

3.4 删除规格

(1)业务层

修改com.offcn.sellergoods.service.SpecificationServiceImpl,删除规格方法,代码如下:

    /**
     * 删除
     * @param id
     */
    @Override
    public void delete(Long id){
        //1.删除规格名称对象
        this.removeById(id);
        //2.关联删除规格选项集合
        QueryWrapper<SpecificationOption> queryWrapper = new QueryWrapper();
        queryWrapper.eq("spec_id", id);
        //执行删除
        specificationOptionMapper.delete(queryWrapper);
    }

(2)控制层

SpecificationController删除方法

    /***
     * 根据ID删除品牌数据
     * @param id
     * @return
     */
    @ApiOperation(value = "Specification根据ID删除",notes = "根据ID删除Specification方法详情",tags = {"SpecificationController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
    @DeleteMapping(value = "/{id}" )
    public Result delete(@PathVariable Long id){
        //调用SpecificationService实现根据主键删除
        specificationService.delete(id);
        return new Result(true,StatusCode.OK,"删除成功");
    }

四 模板管理

**1 **需求分析

首先我们需要理解模板的作用。模板主要有两个:

1是用于关联品牌与规格

2定义扩充属性

2 表结构分析

tb_type_template 模板表

字段 类型 长度 含义
Id Bigint 主键
name Varchar 80 模板名称
spec_ids Varchar 1000 关联规格(json格式)
brand_ids Varchar 1000 关联品牌(json格式)
custom_attribute_items Varchar 2000 扩展属性(Json格式)

3.品牌下拉列表

在弹出窗口中有个品牌下拉列表,要求品牌是可以选择多个,需要后台提供数据支持

3.1 品牌下拉列表代码实现

(1)修改dao层 ,在BrandMapper中添加查询

@Select("select id,name as text from tb_brand")
public List<Map> selectOptions();

(2)修改com.offcn.sellergoods.service.BrandService,增加方法定义

/**
 * 查询品牌下拉列表
 * @return
*/
public List<Map> selectOptions();

(3)修改com.offcn.sellergoods.service.impl.BrandServiceImpl,增加方法

    /**
     * 查询品牌下拉列表
     *
     * @return
     */
    @Override
    public List<Map> selectOptions() {
       return brandMapper.selectOptions();
    }

(4)修改BrandController.java

@ApiOperation(value = "查询品牌下拉列表",notes = "查询品牌下拉列表",tags = {"BrandController"})
@GetMapping("/selectOptions")
public ResponseEntity<List<Map>> selectOptions(){
        return ResponseEntity.ok(brandService.selectOptions());
}

3.2 规格下拉列表代码实现

(1)修改dao层 ,在SpecificationMapper中添加查询

@Select("select id,spec_name as text from tb_specification")
public List<Map> selectOptions();

(2)修改com.offcn.sellergoods.service.SpecificationService,增加方法定义

    /**
     * 查询规格下拉列表
     * @return
     */
    public List<Map> selectOptions();

(3)修改com.offcn.sellergoods.service.impl.SpecificationServiceImpl,增加方法

    /**
     * 查询规格下拉列表
     *
     * @return
     */
    @Override
    public List<Map> selectOptions() {

        return specificationMapper.selectOptions();
    }

(4)修改SpecificationController.java

@ApiOperation(value = "查询规格下拉列表",notes = "查询规格下拉列表",tags = {"SpecificationController"})
@GetMapping("/selectOptions")
public List<Map> selectOptions() {
        return specificationService.selectOptions();
}

五 商品分类

1 需求分析

实现三级商品分类列表查询功能

进入页面首先显示所以一级分类,效果如下:

点击列表行的查询下级按钮,进入下级分类列表,同时更新面包屑导航

2 表结构分析

tb_item_cat 商品分类表

字段 类型 长度 含义
id Bigint 主键
parent_id Bigint 上级ID
name varchar 分类名称
type_id Bigint 模板ID

3 查询下级代码实现

(1)修改com.offcn.sellergoods.service.ItemCatService接口,新增方法定义

  /**
   * 根据父级ID查询分类列表
   * @param parentId
   * @return
   */
  public List<ItemCat> findByParentId(Long parentId);

(2)修改com.offcn.sellergoods.service.impl.ItemCatServiceImpl ,实现方法

    /**
     * 根据父级ID查询分类列表
     *
     * @param parentId
     * @return
     */
    public List<ItemCat> findByParentId(Long parentId) {
        ItemCat itemCat = new ItemCat();
        itemCat.setParentId(parentId);
        QueryWrapper<ItemCat> queryWrapper = this.createQueryWrapper(itemCat);
        return this.list(queryWrapper);
    }

(3)修改ItemCatController.java

@ApiOperation(value = "根据父级ID查询ItemCat",notes = "根据父级ID查询ItemCat",tags = {"ItemCatController"})
@GetMapping("/findByParentId")
public Result<List<ItemCat>> findByParentId(Long parentId) {
        List<ItemCat> list = itemCatService.findByParentId(parentId);
        return new Result<List<ItemCat>>(true, StatusCode.OK,"查询成功",list) ;
}

4 新增商品分类(学员实现)

4.1新增商品分类–实现模板下拉列表(学员实现)

5 修改商品分类(学员实现)

6 删除商品分类(学员实现)

六 电商概念及表结构分析

1. SPU与SKU概念

SPU = Standard Product Unit  (标准产品单位)

  • 概念 : SPU 是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。

  • 通俗点讲,属性值、特性相同的货品就可以称为一个 SPU

    ==同款商品的公共属性抽取==

    例如: Iphone12就是一个SPU,与商家,与颜色、款式、套餐都无关

SKU = stock keeping unit( 库存量单位)

  • SKU 即库存进出计量的单位, 可以是以件、盒、托盘等为单位。

  • SKU 是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。

  • 在服装、鞋类商品中使用最多最普遍。

    ==某个库存单位的商品独有属性(某个商品的独有属性)==

    例如:Iphone12 黑色 128G 全网通 就是一个 SKU

2 表结构分析

Tb_goods 商品表

Tb_goods_desc 商品扩展信息表

Tb_item SKU表

七 新增和修改商品

1 需求分析

实现商品的新增与修改功能。

(1)先选择添加的商品所属分类,选择关联品牌,并填写相关信息

(2)上传图片以及填写关联扩展属性的信息

(3)填写SKU信息

2 实现思路

前端传递给后端的数据格式 是一个spu对象和sku列表组成的对象,如下图:

上图JSON数据如下:

{
  "goods": {
    "brandId": 1,
    "caption": "测试商品01副标题",
    "category1Id": 558,
    "category2Id": 559,
    "category3Id": 560,
    "goodsName": "测试商品01",
    "isEnableSpec": "1",
    "price": "1000",
    "typeTemplateId": 35
  },
  "goodsDesc": {
    "customAttributeItems": "[{"text":"内存大小","value":"16G"},{"text":"颜色","value":"绿色"}]",
    "introduction": "<span style="color:#666666;font-family:tahoma, arial, &quot;font-size:14px;background-color:#FFFFFF;">测试描述</span><br />",
    "itemImages": "[{"color":"红色","url":"http://192.168.188.146/group1/M00/00/00/wKi8kly5gXGAZ9X_AAQQPbR_emI045.png"},{"color":"绿色","url":"http://192.168.188.146/group1/M00/00/00/wKi8kly5gXmANvndAAI1bFuIUJE180.jpg"}]",
    "packageList": "测试包装",
    "saleService": "测试售后服务",
    "specificationItems": "[{"attributeValue":["移动3G","移动4G"],"attributeName":"网络"},{"attributeValue":["16G","32G"],"attributeName":"机身内存"}]"
  },
  "itemList": [
    {     
      "isDefault": "1",
      "num": 9999,
      "price": "1000", 
      "spec": "{"机身内存":"16G","网络":"移动3G"}",
      "status": "1",
    },
	{     
      "isDefault": "0",
      "num": 9999,
      "price": "2000", 
      "spec": "{"机身内存":"16G","网络":"移动4G"}",
      "status": "1",
    },
	{     
      "isDefault": "0",
      "num": 9999,
      "price": "2001", 
      "spec": "{"机身内存":"24G","网络":"移动3G"}",
      "status": "1",
    },
	{     
      "isDefault": "0",
      "num": 9999,
      "price": "2002", 
      "spec": "{"机身内存":"24G","网络":"移动4G"}",
      "status": "1",
    }
  ]
}

3 查询分类级联数据

3.1 需求分析

在实现商品增加之前,需要先选择对应的分类,选择分类的时候,首选选择一级分类,然后根据选中的分类,将选中的分类作为查询的父ID,再查询对应的子分类集合。这块在昨天的代码中已经有一个根据父节点ID查询分类信息的方法,参考findByPrantId方法,首先查询顶级分类,也就是pid=0,然后根据用户选择的分类,将选择的分类作为pid查询子分类。

3.2 代码实现

(1)Dao实现,代码如下:

public interface ItemCatMapper extends BaseMapper<ItemCat> {
}

(2)Service层,代码如下:

    /**
     * 根据父级ID查询分类列表
     * @param parentId
     * @return
     */
    public List<ItemCat> findByParentId(Long parentId);

服务实现,代码如下:

    /**
     * 根据父级ID查询分类列表
     *
     * @param parentId
     * @return
     */
    public List<ItemCat> findByParentId(Long parentId) {
        ItemCat itemCat = new ItemCat();
        itemCat.setParentId(parentId);
        QueryWrapper<ItemCat> queryWrapper = this.createQueryWrapper(itemCat);
        return this.list(queryWrapper);
    }

(3)Controller层,代码如下:

@ApiOperation(value = "根据父级ID查询ItemCat",notes = "根据父级ID查询ItemCat",tags = {"ItemCatController"})
@GetMapping("/findByParentId")
public Result<List<ItemCat>> findByParentId(Long parentId) {
       List<ItemCat> list = itemCatService.findByParentId(parentId);
       return new Result<List<ItemCat>>(true, StatusCode.OK,"查询成功",list) ;
}

4 查询分类下品牌数据

4.1 分析

用户每次选择了分类之后,可以根据用户选择的分类到tb_item_cat表中根据模板ID关联到tb_type_template表中查询品牌,再将品牌集合数据放到前端来展示即可实现上述功能。

4.2 代码实现

(1)Dao实现

com.offcn.sellergoods.dao.TypeTemplateMapper,代码如下:

public interface TypeTemplateMapper extends BaseMapper<TypeTemplate> {
}

(2)Service层,代码如下:

/**
* 根据ID查询TypeTemplate
* @param id
* @return
*/
TypeTemplate findById(Long id);

服务实现,代码如下:

/**
* 根据ID查询TypeTemplate
* @param id
* @return
*/
@Override
public TypeTemplate findById(Long id){
      return  this.getById(id);
}

(3)Controller层,代码如下:

/***
* 根据ID查询TypeTemplate数据
* @param id
* @return
*/
@ApiOperation(value = "TypeTemplate根据ID查询",notes = "根据ID查询TypeTemplate方法详情",tags = {"TypeTemplateController"})
@ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
@GetMapping("/{id}")
public Result<TypeTemplate> findById(@PathVariable Long id){
//调用TypeTemplateService实现根据主键查询TypeTemplate
        TypeTemplate typeTemplate = typeTemplateService.findById(id);
        return new Result<TypeTemplate>(true,StatusCode.OK,"查询成功",typeTemplate);
}

5 规格查询

5.1 分析

用户选择分类后,需要根据所选分类对应的模板ID查询对应的规格以及规格选项,需要单独编写方法查询出规格选项。

上图JSON数据如下:

{
	"options": [
        {
          "id": 114,
          "optionName": "移动2G",
          "specId": 27,
          "orders": 7
        },
        {
          "id": 115,
          "optionName": "联通2G",
          "specId": 27,
          "orders": 8
        },
        {
          "id": 116,
          "optionName": "电信2G",
          "specId": 27,
          "orders": 9
        }
      ],
      "id": 27,
      "text": "网络"
    },
    {
      "options": [
        {
          "id": 118,
          "optionName": "16G",
          "specId": 32,
          "orders": 1
        },
        {
          "id": 119,
          "optionName": "32G",
          "specId": 32,
          "orders": 2
        },
        {
          "id": 120,
          "optionName": "64G",
          "specId": 32,
          "orders": 3
        },
        {
          "id": 121,
          "optionName": "128G",
          "specId": 32,
          "orders": 4
        }
      ],
      "id": 32,
      "text": "机身内存"
}

5.2 代码实现

(1)Service层

修改com.offcn.sellergoods.service.TypeTemplateService添加根据分类ID查询规格列表,代码如下:

/**
 * 根据模板ID查询规格列表
 * @param typeId
 * @return
 */
public List<Map> findSpecList(Long typeId);

(2)服务实现,修改com.offcn.sellergoods.service.impl.TypeTemplateService添加上面方法的实现,代码如下:

@Autowired
private SpecificationOptionMapper specificationOptionMapper;

/**
 * 根据模板ID查询规格列表
 *
 * @param typeId
 * @return
 */
public List<Map> findSpecList(Long typeId) {
    //1.根据模板ID查询模板对象
    TypeTemplate typeTemplate = this.findById(typeId);
    //2.将规格名称JSON结构的字符串转换成JSON对象   [{"id":27,"text":"网络"},{"id":32,"text":"机身内存"}]
    List<Map> specList = JSON.parseArray(typeTemplate.getSpecIds(), Map.class);
    if (!CollectionUtils.isEmpty(specList)) {
        for (Map map : specList) {
            Long specId = new Long((Integer) map.get("id"));    //Map集合中取得数值类型的值默认是整型
            //3.根据规格ID查询规格选项集合
            QueryWrapper<SpecificationOption> queryWrapper = new QueryWrapper();

            queryWrapper.eq("spec_id", specId);
            List<SpecificationOption> specificationOptionList = specificationOptionMapper.selectList(queryWrapper);
            //4.重新将规格选项集合设置回JSON对象中  {"id":27,"text":"网络","options":[{},{},{}]}
            map.put("options", specificationOptionList);
        }
    }
    return specList;
}

(3)Controller层

修改com.offcn.sellergoods.controller.TypeTemplateController添加根据分类ID查询规格数据,代码如下:

@ApiOperation(value = "查询规格及规格选项信息",notes = "查询规格及规格选项信息",tags = {"TypeTemplateController"})
@ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
@GetMapping("/findSpecList/{id}")
public Result<List<Map>> findSpecList(@PathVariable Long id){
    List<Map> list =  typeTemplateService.findSpecList(id);
    return new Result<List<Map>>(true, StatusCode.OK,"查询成功",list) ;
}

6 SPU+SKU保存

6.1 分析

保存商品数据的时候,需要保存Spu和Sku,一个Spu对应多个Sku,我们可以先构建一个Goods对象,将SpuList<Sku>组合到一起,前端将2者数据提交过来,再实现添加操作。

6.2 代码实现

(1)Pojo改造

修改dongyimai-sellergoods-service-api工程创建组合实体类,创建com.offcn.sellergoods.group.GoodsEntity,代码如下:

public class GoodsEntity implements Serializable {

    private Goods goods;      //商品信息 SPU
    private GoodsDesc goodsDesc;   //商品扩展信息
    private List<Item> itemList;   //商品详情 SKU

    //..get..set..toString
}

因为扩展信息是使用SPU的主键,所以需要修改扩展信息的Pojo的ID生成方式为input类型,代码如下:

@ApiModelProperty(value = "SPU_ID",required = false)
@TableId(type = IdType.INPUT)
@TableField(value = "goods_id")
private Long goodsId;//SPU_ID

(2) 业务层

修改com.offcn.sellergoods.service.GoodsService接口,添加保存Goods方法,代码如下:

/***
 * 新增Goods
 * @param goodsEntity
 */
void add(GoodsEntity goodsEntity);

修改com.offcn.sellergoods.service.impl.GoodsServiceImpl类,添加保存Goods的方法实现,代码如下:

@Autowired
private GoodsMapper goodsMapper;
@Autowired
private GoodsDescMapper goodsDescMapper;
@Autowired
private ItemMapper itemMapper;

@Autowired
private ItemCatMapper itemCatMapper;

@Autowired
private BrandMapper brandMapper;

/**
 * 增加Goods
 *
 * @param goods
 */
@Override
public void add(GoodsEntity goodsEntity) {
    goodsEntity.getGoods().setAuditStatus("0");  //审核状态 未审核
    //1.保存SPU 商品信息对象
    goodsMapper.insert(goodsEntity.getGoods());
    //2.获取商品信息对象主键ID ,向商品扩展信息对象中设置主键
    goodsEntity.getGoodsDesc().setGoodsId(goodsEntity.getGoods().getId());
    //3.保存商品扩展信息
    goodsDescMapper.insert(goodsEntity.getGoodsDesc());
    //4.保存SKU 商品详情信息
    if ("1".equals(goodsEntity.getGoods().getIsEnableSpec())) {
            //5.保存SKU 商品详情信息
            if (!CollectionUtils.isEmpty(goodsEntity.getItemList())) {
                for (Item item : goodsEntity.getItemList()) {
                    String title = goodsEntity.getGoods().getGoodsName();
                    //设置SKU的名称  商品名+规格选项
                    Map<String, String> specMap = JSON.parseObject(item.getSpec(), Map.class);    //取得SKU的规格选项,并做JSON类型转换
                    for (String key : specMap.keySet()) {
                        title += specMap.get(key) + " ";
                    }
                    item.setTitle(title);                                       //SKU名称
                    item.setCategoryId(goodsEntity.getGoods().getCategory3Id());     //商品分类 三级
        			item.setCreateTime(new Date());                             //创建时间
        			item.setUpdateTime(new Date());                             //更新时间
        			item.setGoodsId(goodsEntity.getGoods().getId());                   //SPU ID
        			item.setSellerId(goodsEntity.getGoods().getSellerId());           //商家ID
        			//查询分类对象
        			ItemCat itemCat = itemCatMapper.selectById(goodsEntity.getGoods().getCategory3Id());
        			item.setCategory(itemCat.getName());                            //分类名称
        			//查询品牌对象
        			Brand tbBrand = brandMapper.selectById(goodsEntity.getGoods().getBrandId());
        			item.setBrand(tbBrand.getName());                               //品牌名称
        			List<Map> imageList = JSON.parseArray(goodsEntity.getGoodsDesc().getItemImages(), Map.class);
        			if (imageList.size() > 0) {
            			item.setImage((String) imageList.get(0).get("url"));           //商品图片
        			}
                    //保存SKU信息
                    itemMapper.insert(item);

                }
            }
        } else {
            //不启用规格  SKU信息为默认值
            Item item = new Item();
            item.setTitle(goodsEntity.getGoods().getGoodsName());     //商品名称
            item.setPrice(goodsEntity.getGoods().getPrice());      //默认使用SPU的价格
            item.setNum(9999);
            item.setStatus("1");            //是否启用
            item.setIsDefault("1");         //是否默认
            item.setSpec("{}");             //没有选择规格,则放置空JSON结构
            this.setItemValue(goodsEntity, item);
            itemMapper.insert(item);

        }
}

(3)Controller层

修改com.offcn.sellergoods.controller.GoodsController,增加保存Goods方法,代码如下:

/***
 * 新增Goods数据
 * @param goods
 * @return
 */
@ApiOperation(value = "Goods添加",notes = "添加Goods方法详情",tags = {"GoodsController"})
@PostMapping
public Result add(@RequestBody  @ApiParam(name = "Goods复合实体对象",value = "传入JSON数据",required = true) GoodsEntity goodsEntity){
    //调用GoodsService实现添加Goods
    goodsService.add(goodsEntity);
    return new Result(true,StatusCode.OK,"添加成功");
}

测试数据

{
	"goods": {
		"brandId": 1,
		"caption": "测试商品01副标题",
		"category1Id": 558,
		"category2Id": 559,
		"category3Id": 560,
		"goodsName": "测试商品01",
		"isEnableSpec": "1",
		"price": "1000",
		"typeTemplateId": 35
	},
	"goodsDesc": {
		"customAttributeItems": "[{\"text\":\"内存大小\",\"value\":\"16G\"},{\"text\":\"颜色\",\"value\":\"绿色\"}]",
		"introduction": "<span style=\"color:#666666;font-family:tahoma, arial, &quot;font-size:14px;background-color:#FFFFFF;\">测试描述</span><br />",
		"itemImages": "[{\"color\":\"红色\",\"url\":\"http://192.168.188.146/group1/M00/00/00/wKi8kly5gXGAZ9X_AAQQPbR_emI045.png\"},{\"color\":\"绿色\",\"url\":\"http://192.168.188.146/group1/M00/00/00/wKi8kly5gXmANvndAAI1bFuIUJE180.jpg\"}]",
		"packageList": "测试包装",
		"saleService": "测试售后服务",
		"specificationItems": "[{\"attributeValue\":[\"移动3G\",\"移动4G\"],\"attributeName\":\"网络\"},{\"attributeValue\":[\"16G\",\"32G\"],\"attributeName\":\"机身内存\"}]"
	},
	"itemList": [
		{
			"isDefault": "1",
			"num": 9999,
			"price": "1000",
			"spec": "{\"机身内存\":\"16G\",\"网络\":\"移动3G\"}",
			"status": "1"
		},
		{
			"isDefault": "0",
			"num": 9999,
			"price": "2000",
			"spec": "{\"机身内存\":\"16G\",\"网络\":\"移动4G\"}",
			"status": "1"
		},
		{
			"isDefault": "0",
			"num": 9999,
			"price": "2001",
			"spec": "{\"机身内存\":\"24G\",\"网络\":\"移动3G\"}",
			"status": "1"
		},
		{
			"isDefault": "0",
			"num": 9999,
			"price": "2002",
			"spec": "{\"机身内存\":\"24G\",\"网络\":\"移动4G\"}",
			"status": "1"
		}
	]
}

7 根据ID查询商品

7.1 需求分析

需求:根据id 查询SPU和SKU列表 ,显示效果如下:

 "goods": {
      "id": 149187842867985,
      "sellerId": "1",
      "goodsName": "测试商品01",
      "defaultItemId": null,
      "auditStatus": "1",
      "isMarketable": null,
      "brandId": 1,
      "caption": "测试商品01",
      "category1Id": 558,
      "category2Id": 559,
      "category3Id": 560,
      "smallPic": null,
      "price": "2000.00",
      "typeTemplateId": 35,
      "isEnableSpec": "1",
      "isDelete": "1"
    },
    "goodsDesc": {
      "goodsId": 149187842867985,
      "introduction": "<span style=\"color:#666666;font-family:tahoma, arial, &quot;font-size:14px;background-color:#FFFFFF;\">读者评论</span><br />",
      "specificationItems": "[{\"attributeValue\":[\"移动3G\",\"移动4G\"],\"attributeName\":\"网络\"},{\"attributeValue\":[\"16G\",\"32G\"],\"attributeName\":\"机身内存\"}]",
      "customAttributeItems": "[{\"text\":\"内存大小\",\"value\":\"16G\"},{\"text\":\"颜色\",\"value\":\"绿色\"}]",
      "itemImages": "[{\"color\":\"红色\",\"url\":\"http://192.168.188.146/group1/M00/00/00/wKi8kly5gXGAZ9X_AAQQPbR_emI045.png\"},{\"color\":\"绿色\",\"url\":\"http://192.168.188.146/group1/M00/00/00/wKi8kly5gXmANvndAAI1bFuIUJE180.jpg\"}]",
      "packageList": "测试包装",
      "saleService": "测试售后服务"
    },
    "itemList": [
      {
        "id": 1369283,
        "title": "测试商品01移动3G 16G ",
        "sellPoint": null,
        "price": "2001.00",
        "stockCount": null,
        "num": 9999,
        "barcode": null,
        "image": "http://192.168.188.146/group1/M00/00/00/wKi8kly5gXGAZ9X_AAQQPbR_emI045.png",
        "categoryId": 560,
        "status": "1",
        "createTime": "2021-02-08T12:17:45.000+0000",
        "updateTime": "2021-02-08T12:17:45.000+0000",
        "itemSn": null,
        "costPirce": null,
        "marketPrice": null,
        "isDefault": "1",
        "goodsId": 149187842867985,
        "sellerId": "1",
        "cartThumbnail": null,
        "category": "手机",
        "brand": "联想",
        "spec": "{\"机身内存\":\"16G\",\"网络\":\"移动3G\"}",
        "seller": null
      },
      {
        "id": 1369284,
        "title": "测试商品01移动4G 16G ",
        "sellPoint": null,
        "price": "2001.00",
        "stockCount": null,
        "num": 9999,
        "barcode": null,
        "image": "http://192.168.188.146/group1/M00/00/00/wKi8kly5gXGAZ9X_AAQQPbR_emI045.png",
        "categoryId": 560,
        "status": "1",
        "createTime": "2021-02-08T12:17:45.000+0000",
        "updateTime": "2021-02-08T12:17:45.000+0000",
        "itemSn": null,
        "costPirce": null,
        "marketPrice": null,
        "isDefault": "1",
        "goodsId": 149187842867985,
        "sellerId": "1",
        "cartThumbnail": null,
        "category": "手机",
        "brand": "联想",
        "spec": "{\"机身内存\":\"16G\",\"网络\":\"移动4G\"}",
        "seller": null
      }]

7.2 代码实现

(1)业务层

修改dongyimai-sellergoods-service工程,修改com.offcn.sellergoods.service.GoodsService接口,添加根据ID查找方法findById代码如下:

/**
 * 根据ID查询Goods
 * @param id
 * @return
 */
 GoodsEntity findById(Long id);

修改dongyimai-sellergoods-service工程,修改com.offcn.sellergoods.service.impl.GoodsServiceImpl类,修改根据ID查找findById方法,代码如下:

/**
 * 根据ID查询Goods
 *
 * @param id
 * @return
 */
@Override
public GoodsEntity findById(Long id) {
    //1.根据ID查询SPU信息
    Goods goods = goodsMapper.selectById(id);
    //2.根据ID查询商品扩展信息
    GoodsDesc goodsDesc = goodsDescMapper.selectById(id);
    //3.根据ID查询SKU列表
    QueryWrapper<Item> queryWrapper = new QueryWrapper();

    queryWrapper.eq("goods_id", id);
    List<Item> itemList = itemMapper.selectList(queryWrapper);

    //4.设置复合实体对象
    GoodsEntity goodsEntity = new GoodsEntity();
    goodsEntity.setGoods(goods);
    goodsEntity.setGoodsDesc(goodsDesc);
    goodsEntity.setItemList(itemList);
    return goodsEntity;
}

(2)Controller层

修改com.offcn.sellergoods.controller.GoodsController,修改findById方法,代码如下:

/***
 * 根据ID查询Goods数据
 * @param id
 * @return
 */
@ApiOperation(value = "Goods根据ID查询",notes = "根据ID查询Goods方法详情",tags = {"GoodsController"})
@ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
@GetMapping("/{id}")
public Result<GoodsEntity> findById(@PathVariable Long id){
    //调用GoodsService实现根据主键查询Goods
    GoodsEntity goodsEntity = goodsService.findById(id);
    return new Result<GoodsEntity>(true,StatusCode.OK,"查询成功",goodsEntity);
}

8 保存修改

(1)业务层

修改dongyimai-sellergoods-service的GoodsService的update方法,代码如下:

/***
 * 修改Goods数据
 * @param goods
 */
void update(GoodsEntity goodsEntity);

修改dongyimai-sellergoods-service的GoodsServiceImpl ,将SKU列表插入的代码提取出来,封装到私有方法中,代码如下:

private void setItemValue(GoodsEntity goodsEntity, Item item) {
        item.setCategoryId(goodsEntity.getGoods().getCategory3Id());     //商品分类 三级
        item.setCreateTime(new Date());                             //创建时间
        item.setUpdateTime(new Date());                             //更新时间
        item.setGoodsId(goodsEntity.getGoods().getId());                   //SPU ID
        item.setSellerId(goodsEntity.getGoods().getSellerId());           //商家ID
        //查询分类对象
        ItemCat itemCat = itemCatMapper.selectById(goodsEntity.getGoods().getCategory3Id());
        item.setCategory(itemCat.getName());                            //分类名称
        //查询品牌对象
        Brand tbBrand = brandMapper.selectById(goodsEntity.getGoods().getBrandId());
        item.setBrand(tbBrand.getName());                               //品牌名称
        List<Map> imageList = JSON.parseArray(goodsEntity.getGoodsDesc().getItemImages(), Map.class);
        if (imageList.size() > 0) {
            item.setImage((String) imageList.get(0).get("url"));           //商品图片
        }

    }

//保存SKU信息
private void saveItemList(GoodsEntity goodsEntity) {
        if ("1".equals(goodsEntity.getGoods().getIsEnableSpec())) {
            //5.保存SKU 商品详情信息
            if (!CollectionUtils.isEmpty(goodsEntity.getItemList())) {
                for (Item item : goodsEntity.getItemList()) {
                    String title = goodsEntity.getGoods().getGoodsName();
                    //设置SKU的名称  商品名+规格选项
                    Map<String, String> specMap = JSON.parseObject(item.getSpec(), Map.class);    //取得SKU的规格选项,并做JSON类型转换
                    for (String key : specMap.keySet()) {
                        title += specMap.get(key) + " ";
                    }
                    item.setTitle(title);                                       //SKU名称
                    this.setItemValue(goodsEntity, item);
                    //保存SKU信息
                    itemMapper.insert(item);

                }
            }
        } else {
            //不启用规格  SKU信息为默认值
            Item item = new Item();
            item.setTitle(goodsEntity.getGoods().getGoodsName());     //商品名称
            item.setPrice(goodsEntity.getGoods().getPrice());      //默认使用SPU的价格
            item.setNum(9999);
            item.setStatus("1");            //是否启用
            item.setIsDefault("1");         //是否默认
            item.setSpec("{}");             //没有选择规格,则放置空JSON结构
            this.setItemValue(goodsEntity, item);
            itemMapper.insert(item);

        }
}

在add方法中调用 此方法,修改如下:

/**
 * 增加Goods
 * @param goods
 */
@Override
public void add(GoodsEntity goodsEntity){
    goodsEntity.getGoods().setAuditStatus("0");  //审核状态 未审核
    //1.保存SPU 商品信息对象
    goodsMapper.insert(goodsEntity.getGoods());
    //2.获取商品信息对象主键ID ,向商品扩展信息对象中设置主键
    goodsEntity.getGoodsDesc().setGoodsId(goodsEntity.getGoods().getId());
    //3.保存商品扩展信息
    goodsDescMapper.insert(goodsEntity.getGoodsDesc());
    //4.保存商品SKU信息
    this.saveItemList(goodsEntity);
}

怎么样,是不是比原来更加清爽了呢?

接下来,我们修改update方法,实现修改

/**
 * 修改Goods
 * @param goods
 */
@Override
public void update(GoodsEntity goodsEntity){
    //将审核状态重新设置为 未审核
    goodsEntity.getGoods().setAuditStatus("0");
    //1.修改SPU的信息
    goodsMapper.updateById(goodsEntity.getGoods());
    //2.修改商品扩展信息
    goodsDescMapper.updateById(goodsEntity.getGoodsDesc());
    //3.先根据商品ID删除SKU信息
    QueryWrapper<Item> queryWrapper = new QueryWrapper();

    queryWrapper.eq("goods_id", goodsEntity.getGoods().getId());
    itemMapper.delete(queryWrapper);
    //4.重新添加SKU信息
    this.saveItemList(goodsEntity);
}

(2)控制层

修改com.offcn.sellergoods.controller.GoodsController,修改update方法,代码如下:

/***
 * 修改Goods数据
 * @param goods
 * @param id
 * @return
 */
@ApiOperation(value = "Goods根据ID修改",notes = "根据ID修改Goods方法详情",tags = {"GoodsController"})
@ApiImplicitParam(paramType = "path", name = "id", value = "主键ID", required = true, dataType = "Long")
@PutMapping(value="/{id}")
public Result update(@RequestBody @ApiParam(name = "Goods复合实体对象",value = "传入JSON数据",required = false) GoodsEntity goodsEntity,@PathVariable Long id){
    //设置主键值
    goodsEntity.getGoods().setId(id);
    //调用GoodsService实现修改Goods
    goodsService.update(goodsEntity);
    return new Result(true,StatusCode.OK,"修改成功");
}

八 商品审核与上下架(学员实现)

1 需求分析

商品新增后,审核状态为0(未审核),默认为下架状态。

审核商品,需要校验是否是被删除的商品,如果未删除则修改审核状态为1,并自动上架

下架商品,需要校验是否是被删除的商品,如果未删除则修改上架状态为0

上架商品,需要审核通过的商品

2 实现思路

(1)按照ID查询SPU信息

(2)判断修改审核、上架和下架状态

(3)保存SPU

3 代码实现

3.1 商品审核

实现审核通过,自动上架。

(1)业务层

修改dongyimai-sellergoods-service工程的com.offcn.sellergoods.service.GoodsService接口,添加审核方法,代码如下:

/***
 * 商品审核
 * @param goodsId
 */
void audit(Long goodsId);

修改dongyimai-sellergoods-service工程的com.offcn.sellergoods.service.impl.GoodsServiceImpl类,添加audit方法,代码如下:

/***
 * 商品审核
 * @param goodsId
 */
@Override
public void audit(Long goodsId) {
    //查询商品
    Goods goods = goodsMapper.selectById(goodsId);
    //判断商品是否已经删除
    if(goods.getIsDelete().equals("1")){
        throw new RuntimeException("该商品已经删除!");
    }
    //实现上架和审核
    goods.setAuditStatus("1"); //审核通过
    goods.setIsMarketable("1"); //上架
    goodsMapper.updateById(goods);
}

(2)控制层

修改com.offcn.sellergoods.controller.GoodsController,新增audit方法,代码如下:

/**
 * 审核
 * @param id
 * @return
 */
@PutMapping("/audit/{id}")
public Result audit(@PathVariable Long id){
    goodsService.audit(id);
    return new Result(true,StatusCode.OK,"审核成功");
}

3.2 下架商品

(1)业务层

修改com.offcn.sellergoods.service.GoodsService接口,添加pull方法,用于商品下架,代码如下:

/***
 * 商品下架
 * @param goodsId
 */
void pull(Long goodsId);

修改com.offcn.sellergoods.impl.GoodsServiceImpl,添加如下方法:

/**
 * 商品下架
 * @param goodsId
 */
@Override
public void pull(Long goodsId) {
    Goods goods = goodsMapper.selectById(goodsId);
    if(goods.getIsDelete().equals("1")){
        throw new RuntimeException("此商品已删除!");
    }
    goods.setIsMarketable("0");//下架状态
    goodsMapper.updateById(goods);
}

(2)控制层

修改com.offcn.sellergoods.controller.GoodsController,添加pull方法,代码如下:

/**
 * 下架
 * @param id
 * @return
 */
@PutMapping("/pull/{id}")
public Result pull(@PathVariable Long id){
    goodsService.pull(id);
    return new Result(true,StatusCode.OK,"下架成功");
}

3.3 上架商品

必须是通过审核的商品才能上架

(1)业务层

修改com.offcn.sellergoods.service.GoodsService,添加put方法,代码如下:

/***
 * 商品上架
 * @param goodsId
 */
void put(Long goodsId);

修改com.offcn.sellergoods.service.impl.GoodsServiceImpl,添加put方法实现,代码如下:

/***
 * 商品上架
 * @param goodsId
 */
@Override
public void put(Long goodsId) {
    Goods goods = goodsMapper.selectById(goodsId);
    //检查是否删除的商品
    if(goods.getIsDelete().equals("1")){
        throw new RuntimeException("此商品已删除!");
    }
    if(!goods.getAuditStatus().equals("1")){
        throw new RuntimeException("未通过审核的商品不能!");
    }
    //上架状态
    goods.setIsMarketable("1");
    goodsMapper.updateById(goods);
}

(2)控制层

修改com.offcn.sellergoods.controller.GoodsController,添加put方法代码如下:

/**
 * 商品上架
 * @param id
 * @return
 */
@PutMapping("/put/{id}")
public Result put(@PathVariable Long id){
    goodsService.put(id);
    return new Result(true,StatusCode.OK,"上架成功");
}

3.4 批量上架

前端传递一组商品ID,后端进行批量上下架处理

(1)业务层

修改com.offcn.sellergoods.service.GoodsService接口,代码如下:

int putMany(Long[] ids);

修改com.offcn.sellergoods.service.impl.GoodsServiceImpl,添加批量上架方法实现,代码如下:

/***
 * 批量上架
 * @param ids:需要上架的商品ID集合
 * @return
 */
@Override
public int putMany(Long[] ids) {
    Goods goods=new Goods();
    goods.setIsMarketable("1");//上架
    //批量修改
    QueryWrapper<Goods> queryWrapper = new QueryWrapper();

    queryWrapper.in("id", Arrays.asList(ids));
    //下架
    queryWrapper.eq("is_marketable","0");
    //审核通过的
    queryWrapper.eq("audit_status","1");
    //非删除的
    queryWrapper.eq("is_delete","0");
    return goodsMapper.update(goods, queryWrapper);
}

(2)控制层

修改com.offcn.sellergoods.controller.GoodsController,添加批量上架方法,代码如下:

    /**
     *  批量上架
     * @param ids
     * @return
     */
    @PutMapping("/put/many")
    public Result putMany(@RequestBody Long[] ids){
        int count = goodsService.putMany(ids);
        return new Result(true,StatusCode.OK,"上架"+count+"个商品");
    }

3.5 批量下架

学员实现

九 删除与还原商品

1 需求分析

请看管理后台的静态原型

我们为商品管理提供商品删除功能,用户选中部分商品,点击删除按钮即可实现商品删除。注意,这里的删除并非是物理删除,而是修改tb_goods表的is_delete字段为1 ,我们可以称之为“逻辑删除”

2 实现思路

逻辑删除商品,修改spu表is_delete字段为1

3 代码实现

3.1 逻辑删除商品

(1)业务层

修改com.offcn.sellergoods.service.impl.GoodsServiceImpl接口,修改delete方法,代码如下:

 /**
  * 删除
  *
  * @param id
  */
 @Override
 public void delete(Long id) {
     // 逻辑删除
     Goods goods = goodsMapper.selectById(id);
     //检查是否下架的商品
     if (!goods.getIsMarketable().equals("0")) {
         throw new RuntimeException("必须先下架再删除!");
     }
     goods.setIsDelete("1");
     //未审核
     goods.setAuditStatus("0");
     goodsMapper.updateById(goods);
 }

(2)控制层

修改com.offcn.sellergoods.controller.GoodsController,添加delete方法,如下:

/***
 * 根据ID删除品牌数据
 * @param id
 * @return
 */
@ApiOperation(value = "Goods根据ID删除",notes = "根据ID删除Goods方法详情",tags = {"GoodsController"})
@ApiImplicitParam(paramType = "path", name = "id", value = "主键ID集合", required = true, dataType = "Long")
@DeleteMapping("/{id}")
public Result delete(@PathVariable Long id){
    //调用GoodsService实现根据主键删除
    goodsService.delete(id);
    return new Result(true,StatusCode.OK,"删除成功");
}

十 注解式事务配置

1 事务异常测试

我们修改dongyimai-sellergoods-service工程GoodsServiceImpl.java的add方法

/**
 * 增加Goods
 *
 * @param goods
 */
@Override
public void add(GoodsEntity goodsEntity) {
    goodsEntity.getGoods().setAuditStatus("0");  //审核状态 未审核
    //1.保存SPU 商品信息对象
    goodsMapper.insert(goodsEntity.getGoods());
    //2.获取商品信息对象主键ID ,向商品扩展信息对象中设置主键
    goodsEntity.getGoodsDesc().setGoodsId(goodsEntity.getGoods().getId());
    //3.保存商品扩展信息
    goodsDescMapper.insert(goodsEntity.getGoodsDesc());
    
    int i = 1 / 0;
    
    //4.保存商品SKU信息
    this.saveItemList(goodsEntity);
}

在插入商品表和扩展表后,人为制造一个异常。我们运行程序,新增商品数据,观察运行结果。

通过观察,我们发现,程序发生异常 ,商品表仍然会存储记录,这是不符合我们要求的。这是因为我们目前的系统还没有配置事务。

2 注解式事务解决方案

在项目pom.xml文件中,因为引入了spring-boot-starter-jdbc,会注入一个DataSourceTransactionManager的 bean,提供了事务支持

@Transactional

这个注解可以放在类上,也可以放在方法上;如果是标注在类上,则这个类的所有公共方法,都支持事务;

如果类和方法上都有,则方法上的注解相关配置,覆盖类上的注解

@Service
@Transactional
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
    
	//此处略
        
}

经过测试,我们发现,系统发生异常,商品表不会新增记录,事务配置成功。

删除掉测试代码int x=1/0

我们需要将所有涉及多表操作的服务类添加事务注解,例如SpecificationServiceImpl类


avatar
青山
悟已往之不谏 知来者之可追
一言
今日诗词
站点信息
本站访客数 :
本站总访问量 :