Java - stage03 - day13 - day14 - 商品模块

1. 商品分类实现

1.1 环境搭建

1.1.1 表设计

表说明:模块大部分都是单表查询方式

CREATE TABLE `item_cat` (
  `id` int NOT NULL AUTO_INCREMENT,
  `parent_id` int DEFAULT NULL,
  `name` varchar(150) DEFAULT NULL,
  `status` int DEFAULT NULL,
  `level` int DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `updated` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1194 DEFAULT CHARSET=utf8mb3;

1.1.2 项目改造

1.1.2.1 导入jar包
<!--Mybatis Plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
</dependency>
1.1.2.2 编辑ItemCat POJO
package com.jt.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;

@Data
@Accessors(chain = true)
@TableName("item_cat")
public class ItemCat extends BasePojo{

    @TableId(type = IdType.AUTO)
    private Integer id;         //定义主键
    private Integer parentId;   //定义父级菜单
    private String name;        //分类名称
    private Boolean status;     //分类状态 0 停用 1 正常
    private Integer level;      //商品分类等级  1 2 3
    /**
     * 属性SQL不负责操作
     */
    @TableField(exist = false)
    private List<ItemCat> children;
}
1.1.2.3 编辑ItemCat Mapper
package com.jt.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.ItemCat;

public interface ItemCatMapper extends BaseMapper<ItemCat> {
    //CURD操作如果没有特殊需求可以省略
    //如果没有sql的需求,则xml映射文件可以简化
}
1.1.2.4 编辑yml配置文件
#SpringBoot整合mybatisPlus
mybatis-plus:
  #指定别名包
  type-aliases-package: com.jt.pojo
  #加载指定的xml映射文件
  mapper-locations: classpath:/mybatis/mappers/*.xml
  #开启驼峰映射
  configuration:
    map-underscore-to-camel-case: true
1.1.2.5 层级代码搭建

在这里插入图片描述

2. ItemCat 列表实现

  1. Html
<!-- 2.2定义表格数据-->
      <el-table :data="itemCatList" style="width: 100%;margin-bottom: 20px;" row-key="id" border stripe>
        <el-table-column type="index" label="序号">
        </el-table-column>
        <el-table-column prop="name" label="分类名称">
        </el-table-column>
        <el-table-column prop="status" label="状态">
          <!-- 定义作用域插槽 展现数据     scope.row展现行级元素 -->
          <template slot-scope="scope">
            <el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949"
              @change="updateStatus(scope.row)"></el-switch>
          </template>
        </el-table-column>
        <el-table-column prop="level" label="等级">
          <!-- 定义作用域插槽 定义标签等级-->
          <template slot-scope="scope">
            <el-tag effect="dark" v-if="scope.row.level == 1">一级分类</el-tag>
            <el-tag effect="dark" type="warning" v-if="scope.row.level == 2">二级分类</el-tag>
            <el-tag effect="dark" type="danger" v-if="scope.row.level == 3">三级分类</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <!-- 定义作用域插槽 定义标签等级-->
          <template slot-scope="scope">
            <el-button type="success" icon="el-icon-edit" @click="updateItemCatBtn(scope.row)">编辑</el-button>
            <el-button type="danger" icon="el-icon-delete" @click="deleteItemCatBtn(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
  1. JS
export default {
    //定义初始化函数
    created() {
      //默认获取商品分类列表数据
      this.findItemCatList()
    },
	methods: {
      async findItemCatList() {
        const {
          data: result
        } = await this.$http.get("/itemCat/findItemCatList/3")
        if (result.status !== 200) return this.$message.error("获取商品分类列表失败!!")
        this.itemCatList = result.data
      },
    }
}
  1. ItemCatController
    /**
     * 需求: 查询3级分类数据信息
     * URL: /itemCat/findItemCatList/{level}
     */
    @GetMapping("/findItemCatList/{level}")
    public SysResult findItemCatList(@PathVariable Integer level) {

        List<ItemCat> list = itemCatService.findItemCatList(level);
        return SysResult.success(list);
    }
  1. ItemCatServiceImpl
@Override
    public List<ItemCat> findItemCatList(Integer level) {
        long startTime = System.currentTimeMillis();
        Map<Integer, List<ItemCat>> map = getMap();

        if(level == 1) {
            return map.get(0);
        }

        if(level == 2) {
            return getTwoList(map);
        }
        List<ItemCat> threeList = getThreeList(map);
        long endTime = System.currentTimeMillis();
        System.out.println((endTime - startTime) + "毫秒");
        return threeList;
    }

	private List<ItemCat> getTwoList(Map<Integer, List<ItemCat>> map) {
        List<ItemCat> catList = map.get(0);
        for(ItemCat oneItemCat : catList) {
            int parentId = oneItemCat.getId();
            List<ItemCat> twoList = map.get(parentId);
            oneItemCat.setChildren(twoList);
        }

        return catList;
    }

    private List<ItemCat> getThreeList(Map<Integer, List<ItemCat>> map) {
        List<ItemCat> oneList = getTwoList(map);
        for(ItemCat itemCat : oneList){
            List<ItemCat> twoList = itemCat.getChildren();
            if(twoList == null || twoList.size() == 0) {
                continue;
            }
            for(ItemCat twoItemCat : twoList) {
                int parentId = twoItemCat.getId();
                List<ItemCat> threeList = map.get(parentId);
                twoItemCat.setChildren(threeList);
            }
        }

        return oneList;
    }

3. ItemCat 增加

  1. html
	<el-row>
      <el-col :span="24">
        <el-button type="primary" @click="showAddItemCatDialog">新增分类</el-button>
      </el-col>
    </el-row>
<!-- 添加新增分类对话框-->
    <el-dialog title="新增商品分类" :visible.sync="addItemCatDialogVisible" width="50%" @close="closeAddItemCatDialog">
      <!-- 定义分类表单 -->
      <el-form :model="itemCatForm" :rules="rules" ref="itemCatFormRef" label-width="100px">
        <el-form-item label="分类名称:" prop="name">
          <el-input v-model="itemCatForm.name"></el-input>
        </el-form-item>
        <!-- 定义父级分类选项 -->
        <el-form-item label="父级分类名称:">
          <!-- 通过级联选择器定义1/2级商品分类
             步骤:  1.注意标签导入
                    2.options 表示数据的来源
                    3.指定props属性指定数据配置
          -->
          <el-cascader v-model="selectedKeys" :props="props" :options="parentItemCatList" clearable
            @change="parentItemCatChange"></el-cascader>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addItemCatDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addItemCatForm">确 定</el-button>
      </span>
    </el-dialog>
  1. JS
data(){
	return {
		//定义商品分类校验规则
        rules: {
          name: [{
            required: true,
            message: '请输入分类名称',
            trigger: 'blur'
          }]
        },
	}
},
methods:{
	showAddItemCatDialog() {
	  this.findParentItemCatList()
	  this.addItemCatDialogVisible = true
	},
	async findParentItemCatList() {
	  //动态获取商品分类信息  type=2表示获取2级商品分类信息
	  const {
	    data: result
	  } = await this.$http.get("/itemCat/findItemCatList/2")
	  if (result.status !== 200) return this.$message.error("获取商品分类列表失败!!")
	  this.parentItemCatList = result.data
	},
	async addItemCatForm() {
	  //先将整个表单进行校验
	  this.$refs.itemCatFormRef.validate(async validate => {
	    if (!validate) return
	    const {
	      data: result
	    } = await this.$http.post("/itemCat/saveItemCat", this.itemCatForm)
	    if (result.status !== 200) return this.$message.error("新增商品分类失败")
	    this.$message.success("新增商品分类成功!!!")
	    //新增成功,则刷新分类列表信息
	    this.findItemCatList();
	    this.addItemCatDialogVisible = false
	  })
	}
}
  1. ItemCatController
@PostMapping("/saveItemCat")
public SysResult saveItemCat(@RequestBody ItemCat itemCat) {

    itemCatService.saveItemCat(itemCat);
    return SysResult.success();
}
  1. ItemCatServiceImpl
    //优化:自动生成时间
    @Override
    @Transactional
    public void saveItemCat(ItemCat itemCat) {
//        Date date = new Date();
        itemCat.setStatus(true);
//                .setCreated(date)
//                .setUpdated(date);
        itemCatMapper.insert(itemCat);
    }
  1. BasePojo
    实现created、updated自动生成
//pojo基类,完成2个任务,2个日期,实现序列化
@Data
@Accessors(chain=true)
public class BasePojo implements Serializable{

	//自动填充
	@TableField(fill = FieldFill.INSERT)
	private Date created;	//表示入库时需要赋值
	@TableField(fill = FieldFill.INSERT_UPDATE)
	private Date updated;	//表示入库/更新时赋值.
}
  1. ItemCat
@Data
@Accessors(chain = true)
@TableName("item_cat")
public class ItemCat extends BasePojo{

    @TableId(type = IdType.AUTO)
    private Integer id;         //定义主键
    private Integer parentId;   //定义父级菜单
    private String name;        //分类名称
    private Boolean status;     //分类状态 0 停用 1 正常
    private Integer level;      //商品分类等级  1 2 3
    /**
     * 属性SQL不负责操作
     */
    @TableField(exist = false)
    private List<ItemCat> children;
}

4. ItemCat修改

  1. html
<el-table-column label="操作">
  <!-- 定义作用域插槽 定义标签等级-->
  <template slot-scope="scope">
    <el-button type="success" icon="el-icon-edit" @click="updateItemCatBtn(scope.row)">编辑</el-button>
    <el-button type="danger" icon="el-icon-delete" @click="deleteItemCatBtn(scope.row)">删除</el-button>
  </template>
</el-table-column>
<!-- 添加修改分类对话框 -->
    <el-dialog title="修改商品分类" :visible.sync="updateItemCatDialogVisible" width="50%">
      <!-- 定义分类表单 -->
      <el-form :model="updateItemCatForm" :rules="rules" ref="upDateItemCatForm" label-width="100px">
        <el-form-item label="分类名称:" prop="name">
          <el-input v-model="updateItemCatForm.name"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="updateItemCatDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="updateItemCat">确 定</el-button>
      </span>
    </el-dialog>
  1. js
updateItemCatBtn(itemCat) {
  this.updateItemCatForm = itemCat
  this.updateItemCatDialogVisible = true
},
async updateItemCat() {
  //修改商品分类信息
  const {
    data: result
  } = await this.$http.put('/itemCat/updateItemCat', this.updateItemCatForm)
  if (result.status !== 200) return this.$message.error("更新商品分类失败")
  this.$message.success("更新商品分类成功")
  this.findItemCatList();
  this.updateItemCatDialogVisible = false;
},
  1. Controller
    @PutMapping("/updateItemCat")
    public SysResult updateItemCat(@RequestBody ItemCat itemCat) {
        System.out.println(itemCat);
        itemCatService.updateItemCat(itemCat);
        return SysResult.success();
    }
  1. ItemCatServiceImpl
    @Override
    @Transactional
    public void updateItemCat(ItemCat itemCat) {
        ItemCat temp = new ItemCat();
        temp.setId(itemCat.getId())
                .setName(itemCat.getName());
        itemCatMapper.updateById(temp);
    }

5. 商品管理模块

前端

<!-- 定义卡片 -->
<template>
  <div>
    <!-- 定义面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>商品列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 定义卡片 -->
    <el-card class="box-card">

      <!-- 定义第一行数据 -->
      <el-row :gutter="20">
        <el-col :span="8">
          <el-input placeholder="请输入内容" v-model="queryItemInfo.query" clearable @clear="getItemList">
            <el-button slot="append" icon="el-icon-search" @click="getItemList"></el-button>
          </el-input>
        </el-col>
        <el-col :span="4">
          <el-button type="primary" @click="toAddItem">添加商品</el-button>
        </el-col>
      </el-row>

      <!-- 获取商品列表数据 -->
      <el-table :data="itemList" style="width: 100%" stripe border>
        <el-table-column type="index" label="序号" width="50px">
        </el-table-column>
        <el-table-column prop="title" label="商品标题" width="400px">
        </el-table-column>
        <el-table-column prop="sellPoint" label="卖点信息" width="300px">
        </el-table-column>
        <!-- 使用过滤器修改时间 在main.js中定义过滤器 -->
        <el-table-column prop="price" label="价格(元)" width="80px">
          <template slot-scope="scope">
            {{scope.row.price | priceFormat}}
          </template>
        </el-table-column>
        <el-table-column prop="num" label="数量" width="80px">
        </el-table-column>
        <el-table-column prop="status" label="状态" width="80px">
          <template slot-scope="scope">
            <el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949"
              @change="updateStatus(scope.row)"></el-switch>
          </template>
        </el-table-column>
       <!-- <el-table-column prop="updated" label="更新时间" width="180px" :formatter="formatDate">
        </el-table-column> -->
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button type="primary" icon="el-icon-edit" size="mini" @click="updateItemBtn(scope.row)">修改</el-button>
            <el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteItemBtn(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- 定义分页插件-->
      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
        :current-page="queryItemInfo.pageNum" :page-sizes="[1, 5, 10, 20]" :page-size="queryItemInfo.pageSize"
        layout="total, sizes, prev, pager, next, jumper" :total="total">
      </el-pagination>
    </el-card>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        //1.定义商品列表信息
        itemList: [],
        //2.定义分页对象
        queryItemInfo: {
          query: '', //定义查询参数
          pageNum: 1,
          pageSize: 10
        },
        total: 0
      }
    },
    created() {
      //1.获取商品列表数据
      this.getItemList()
    },
    methods: {
      //实现商品信息分页查询
      async getItemList() {
        const {
          data: result
        } = await this.$http.get("/item/getItemList", {
          params: this.queryItemInfo
        })
        if (result.status !== 200) return this.$message.error("商品列表查询失败")
        this.itemList = result.data.rows
        this.total = result.data.total
      },
      //通过JS格式化时间
      formatDate(row, column, cellValue, index) {
        let date = new Date(cellValue)
        let year = date.getFullYear()
        let month = (date.getMonth() + 1 + '').padStart(2, '0')
        let day = (date.getDate() + '').padStart(2, '0')
        let HH = (date.getHours() + '').padStart(2, '0')
        let MM = (date.getMinutes() + '').padStart(2, '0')
        let SS = (date.getSeconds() + '').padStart(2, '0')
        return year + '-' + month + '-' + day + ' ' + HH + ":" + MM + ":" + SS
      },
      //条数变化时 调用
      handleSizeChange(size) {
        this.queryItemInfo.pageSize = size
        this.getItemList()
      },
      //页码值变化时 调用
      handleCurrentChange(current) {
        this.queryItemInfo.pageNum = current
        this.getItemList()
      },
      async updateStatus(item) {
        const {
          data: result
        } = await this.$http.put("/item/updateItemStatus", {
          id: item.id,
          status: item.status
        })
        if (result.status !== 200) return this.$message.error("更新状态失败")
        this.$message.success("更新状态成功")
      },
      async deleteItemBtn(item) {
        //消息确认框
        this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(async () => {
          //根据id删除数据
          const {
            data: result
          } = await this.$http.delete("/item/deleteItemById", {
            params: {
              id: item.id
            }
          })
          if (result.status !== 200) return this.$message.error("商品删除失败")
          this.$message.success("商品删除成功")
          //重新获取商品列表信息
          this.getItemList()
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '已取消删除'
          });
        });
      },
      //转向到商品新增页面
      toAddItem(){
        this.$router.push("/item/addItem")
      },
      updateItemBtn(row){
        // console.log(row)
        this.$router.push(`/item/editItem/${row.id}`)
      }
    }
  }
</script>
<!-- 防止组件样式冲突 -->
<style lang="less" scoped>

</style>

5.1 商品列表

  1. pojo/Item
package com.jt.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@TableName("item")
public class Item extends BasePojo{
    @TableId(type = IdType.AUTO)
    private Integer id;         //商品Id号
    private String title;       //商品标题信息
    private String sellPoint;   //卖点信息
    private Integer price;      //商品价格
    private Integer num;        //商品数量
    private String images;       //商品图片
    private Integer itemCatId;  //商品分类ID号
    private Boolean status;     //状态信息    0 下架 1 上架
}
  1. vo/PageResult
package com.jt.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class PageResult {
    private String query;       //查询数据
    private Integer pageNum;    //页数
    private Integer pageSize;   //条数
    private Long total;         //总数
    private Object rows;        //查询结果
}
  1. service/ItemServiceImpl.java
    @Override
    public PageResult getItemList(PageResult pageResult) {
        //判断用户的数据是否有值
        boolean flag = StringUtils.hasLength(pageResult.getQuery());
        QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(flag,"title", pageResult.getQuery());
        IPage<Item> page = new Page<>(pageResult.getPageNum(), pageResult.getPageSize());
        page = itemMapper.selectPage(page, queryWrapper);
        //获取总数
        long total = page.getTotal();
        //获取记录数
        List<Item> rows = page.getRecords();

        return pageResult.setTotal(total).setRows(rows);
    }
  1. Controller
    /**
     * url: /item/getItemList?query=&pageNum=1&pageSize=10
     * 参数: pageResult
     * 返回值:SysResult(pageResult)
     */
    @GetMapping("/getItemList")
    public SysResult getItemList(PageResult pageResult){

        pageResult = itemService.getItemList(pageResult);
        System.out.println(pageResult);
        return SysResult.success(pageResult);
    }

5.2 修改商品状态

  1. Controller
    @PutMapping("/updateItemStatus")
    public SysResult updateItemStatus(@RequestBody Item item) {
        itemService.statusItem(item);
        return SysResult.success();
    }
  1. ServiceImpl
    @Override
    public void statusItem(Item item) {
        itemMapper.updateById(item);
    }

5.3 删除商品

  1. Controller
    /**
     * URL:/item/deleteItemById?id=13
     */
    @DeleteMapping("/deleteItemById")
    public SysResult deleteItemById(Item item) {
        itemService.deleteItem(item);
        return SysResult.success();
    }
  1. ServiceImpl
    @Override
    public void deleteItem(Item item) {
        itemMapper.deleteById(item);
    }

5.4 商品新增

<template>
  <div>
    <!-- 定义面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>商品新增</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 定义卡片视图 -->
    <el-card class="box-card">
      <!-- 定义页面提示信息 -->
      <el-alert title="新增商品流程" type="info" effect="dark" center show-icon :closable="false"></el-alert>
      <!-- 定义步骤条 字符串需要转化为数值 -->
      <el-steps :active="activeIndex - 0" finish-status="success" align-center>
        <el-step title="基本信息"></el-step>
        <el-step title="商品图片"></el-step>
        <el-step title="商品内容"></el-step>
        <el-step title="完成"></el-step>
      </el-steps>
      <!-- 定义标签页 before-leave:切换标签之前的钩子,若返回 false 或者返回 Promise 且被 reject,则阻止切换。 -->
      <el-form :model="addItemForm" :rules="addItemFormRules" ref="addItemFormRef" label-width="100px"
        label-position="top">
        <el-tabs v-model="activeIndex" :tab-position="'left'" :before-leave="beforeLeave">
          <el-tab-pane label="基本信息" name="0">
            <el-form-item label="商品标题" prop="title">
              <el-input v-model="addItemForm.title"></el-input>
            </el-form-item>
            <el-form-item label="商品卖点" prop="sellPoint">
              <el-input v-model="addItemForm.sellPoint"></el-input>
            </el-form-item>
            <el-form-item label="商品价格" prop="price">
              <el-input v-model="addItemForm.price" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品数量" prop="num">
              <el-input v-model="addItemForm.num" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品分类信息" prop="price">
              <!-- 通过级联获取商品分类信息-->
              <el-cascader v-model="itemCatIds" :options="itemCatList" :props="props" @change="changeCascader">
              </el-cascader>
            </el-form-item>
          </el-tab-pane>
          <!-- 实现图片上传 multiple支持多选文件 -->
          <el-tab-pane label="商品图片" name="1">
            <el-upload class="upload-demo" :action="uploadUrl" :on-preview="handlePreview" :on-remove="handleRemove"
              :on-success="handleSuccess" list-type="picture" multiple drag>
              <el-button size="small" type="primary">点击上传</el-button>
              <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
            </el-upload>
          </el-tab-pane>
          <el-tab-pane label="商品详情" name="2">
            <!-- 定义富文本编辑器-->
            <quill-editor ref="myQuillEditor" v-model="itemDesc.itemDesc">
            </quill-editor>
            <!-- 定义添加商品按钮-->
            <el-button type="primary" class="addItemBtnClass" @click="addItemBtn">添加商品</el-button>
          </el-tab-pane>
        </el-tabs>
      </el-form>
    </el-card>
    <!-- 定义图片展现对话框 -->
    <el-dialog title="图片预览" :visible.sync="dialogImageVisible">
      <img :src="imageUrlPath" width="100%" height="100%" />
    </el-dialog>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        activeIndex: '0',
        addItemForm: {
          title: '',
          sellPoint: '',
          price: 0,
          num: 0,
          itemCatId: '',
          images: []
          //itemDesc: '',
          //dynamicArgs: [],
          //staticArgs: []
        },
        itemDesc: {
          itemDesc: ""
        },
        itemParam: {
          dynamicArray: [],
          staticArray: [],
          dynamicArgs: "",
          staticArgs: ""
        }
        ,
        addItemFormRules: {
          title: [{
            required: true,
            message: '请输入商品标题信息',
            trigger: 'blur'
          }],
          sellPoint: [{
            required: true,
            message: '请输入商品卖点信息',
            trigger: 'blur'
          }],
          price: [{
            required: true,
            message: '请输入商品价格信息',
            trigger: 'blur'
          }],
          num: [{
            required: true,
            message: '请输入商品数量信息',
            trigger: 'blur'
          }],

        },
        itemCatIds: [],
        itemCatList: [],
        props: {
          expandTrigger: 'hover',
          value: "id", //选中数据的value值
          label: "name", //选中数据展现名称
          children: "children", //自选项数据
        },
        //设置商品动态参数
        dynamicTableData: [],
        staticTableData: [],

        //定义文件上传路径地址
        uploadUrl: "http://manage.jt.com/file/upload",
        // uploadUrl: "http://localhost:8091/file/upload",
        // uploadUrl: "http://localhost:8091/file/uploadt2",
        //uploadUrl: "http://manage.harrylyj.com/file/upload",
        //定义图片网络访问地址
        imageUrlPath: "",
        //定义图片控制开关
        dialogImageVisible: false
      }
    },
    created() {
      this.findItemCatList()
    },
    methods: {
      //1.获取所有商品分类信息
      async findItemCatList() {
        const {
          data: result } = await this.$http.get("/itemCat/findItemCatList/3")
        if (result.status !== 200) return this.$message.error("查询商品分类信息失败")
        this.itemCatList = result.data
      },
      //修改商品分类选项
      changeCascader() {
        this.addItemForm.itemCatId = this.itemCatIds[2]
        //console.log(this.addItemForm.itemCatId)
      },
      //当标签页数据没有完成选择时 不让切换标签页
      beforeLeave(activeName, oldActiveName) {
        //console.log(this.itemCatIds.length)
        //console.log(typeof(oldActiveName))
        //注意oldActiveName的数据类型为字符串
        if (this.itemCatIds.length !== 3 && oldActiveName === '0') {
          this.$message.error("请先选择商品分类")
          return false
        }
      },
      //预览图片的方法
      handlePreview(file) {
        //获取图片的虚拟路径
        this.imageUrlPath = file.response.data.urlPath
        this.dialogImageVisible = true
      },
      //移除图片的方法
      async handleRemove(file) {
        //移除数组中的数据
        let virtualPath = file.response.data.virtualPath
        //通过findIndex函数 获取数组中指定数据的位置
        let index = this.addItemForm.images.findIndex(x => x === virtualPath)
        //删除数组中指定的数据
        this.addItemForm.images.splice(index, 1)
        //删除服务中的文件
        let {
          data: result
        } = await this.$http.delete("/file/deleteFile", {
          params: {
            virtualPath: virtualPath
          }
        })
        if (result.status !== 200) return this.$message.error("删除图片失败")
        this.$message.success("删除图片成功")
      },
      //如果文件上传成功之后调用
      handleSuccess(response, file) {
        if (response.status !== 200) return this.$message.error("文件上传失败")
        file.name = response.data.fileName
        //获取虚拟路径
        let virtualPath = response.data.virtualPath
        //将数据封装到Form表单中
        this.addItemForm.images.push(virtualPath)
      },

      /* 添加商品按钮 */
      async addItemBtn(){
        //console.log(this.addItemForm)

        //1.完成表单校验
        this.$refs.addItemFormRef.validate( valid => {
          if(!valid) return this.$message.error("请输入商品必填项")
        })

        //2.完成商品参数的封装
        //2.0 将商品价格扩大100倍
        this.addItemForm.price = this.addItemForm.price * 100
        //2.1 将商品图片的数据转化为字符串
        this.addItemForm.images = this.addItemForm.images.join(",")

        //2.5 实现商品数据提交
        let submitAddItem = {
          item : this.addItemForm,
          itemDesc: this.itemDesc
        }
        console.log(submitAddItem)
        let {data: result} = await this.$http.post("/item/saveItem",submitAddItem)
        if(result.status !== 200) return this.$message.error("商品添加失败")
        this.$message.success("商品添加成功")

        //2.5添加完成之后,将数据重定向到商品展现页面
        this.$router.push("/item")
      }
    }
  }
</script>

<style lang="less" scoped>
  .el-steps {
    margin: 20px 0;
  }
  .el-cascader {
    width: 30%;
  }
  /* 控制复选框的右边距5像素 !important 表示优先执行 IE6不兼容*/
  .el-checkbox {
    margin: 0 10px 0 0 !important;
  }
  .addItemBtnClass{
    margin-top: 15px;
  }
</style>
  1. Controller
    /**
     * 需求:实现商品新增
     * URL:http://localhost:8091/item/saveItem
     * 参数:{item: this.addItemForm, itemDesc: this.itemDesc}
     * 接收数据: ItemVO
     * 返回值:SysResult对象
     */
    @PostMapping("/saveItem")
    public SysResult saveItem(@RequestBody ItemVO itemVO) {
        itemService.saveItem(itemVO);
        return SysResult.success();
    }
  1. ItemVO
package com.jt.vo;

import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ItemVO {  //该对象封装商品所有的参数信息
    private Item item;
    private ItemDesc itemDesc;
}
  1. Item pojo
package com.jt.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@TableName("item")
public class Item extends BasePojo{
    @TableId(type = IdType.AUTO)
    private Integer id;         //商品Id号
    private String title;       //商品标题信息
    private String sellPoint;   //卖点信息
    private Integer price;      //商品价格
    private Integer num;        //商品数量
    private String images;       //商品图片
    private Integer itemCatId;  //商品分类ID号
    private Boolean status;     //状态信息    0 下架 1 上架

}
  1. ItemServiceImpl
    @Override
    @Transactional
    public void saveItem(ItemVO itemVO) {
        Item item = itemVO.getItem();
        item.setStatus(true);
        //MP数据入库之后,数据自动回显,可以获取新增ID
        itemMapper.insert(item);
        ItemDesc itemDesc = itemVO.getItemDesc();
        itemDesc.setId(item.getId());
        itemDescMapper.insert(itemDesc);
    }

5.5 商品图片上传

  1. Controller
    @PostMapping("/upload")
    public SysResult upload2(MultipartFile file) {

        ImageVO imageVO = fileService.upload(file);
        return SysResult.success(imageVO);
    }
    
    @DeleteMapping("/deleteFile")
    public SysResult deleteFile(String virtualPath) {

        fileService.deleteFile(virtualPath);
        return SysResult.success();
    }
  1. FileServiceImpl
package com.jt.service;

import com.jt.vo.ImageVO;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService {

//    private String localDir = "D:/w/tmp/jt";
    private String localDir = "/opt/web/images";
    private String urlPath = "http://image.jt.com";

    /**
     * 1. 校验图片类型        xx.jpg
     * 2. 校验是否为恶意程序   xx.exe.jpg
     * 3. 将文件分目录存储
     * 4. 为了保证图片唯一性,自定义文件名称
     *
     * @param file
     * @return
     */
    @Override
    public ImageVO upload(MultipartFile file) {
        String fileName = file.getOriginalFilename().toLowerCase();
        if(!fileName.matches("^.+\\.(jpg|png|gif)$")){
            return null;
        }
        //图片类型正确
        try {
            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
            int width = bufferedImage.getWidth();
            int height = bufferedImage.getHeight();
            if(width == 0 || height == 0) {
                return null;
            }

            String dateDir = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());

            // E:/images + /2022/11/11/
            String dirPath = localDir + dateDir;
            File dirFile = new File(dirPath);
            if(!dirFile.exists()) {
                dirFile.mkdirs();
            }
            System.out.println("用户上传的是图片");
            String uuid = UUID.randomUUID()
                                .toString().replace("-", "");
            int index = fileName.lastIndexOf(".");
            String fileType = fileName.substring(index);
            String newFile = uuid + fileType;
            String path = dirPath + newFile;
            file.transferTo(new File(path));

            String virtualPath = dateDir + newFile;
            String fileNameVO = newFile;

            String url = urlPath + virtualPath;
            System.out.println(url);
            return new ImageVO(virtualPath, url, fileNameVO);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void deleteFile(String virtualPath) {

        String path = localDir + virtualPath;
        File file = new File(path);
        if(file.exists()) {
            file.delete();
        }
    }
}
  1. ImageVO
package com.jt.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {
    private String virtualPath;
    private String urlPath;
    private String fileName;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值