11 商品模块实现

1 完成商品分类业务

1.1 页面JS分析

  1. 生命周期函数
	//定义初始化函数
    created() {
      //默认获取商品分类列表数据
      this.findItemCatList()
    },

  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
      },

1.2 业务接口文档

  • 请求路径: /itemCat/findItemCatList/{level}
  • 请求类型: get
  • 请求参数: level
参数名称参数说明备注
level查询级别1查询一级分类 2查询1-2 级商品分类 3查询1-2-3级商品分类
  • 业务说明: 查询3级分类菜单数据 要求三层结构嵌套
  • 返回值: SysResult对象
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据3级商品分类信息

1.3 商品分类表结构说明

  1. 表结构
    请添加图片描述

  2. sql案例练习

/*所有的一级菜单 parent_id=0*/
SELECT * FROM item_cat WHERE parent_id = 0
/*查询汽车用户的二级菜单*/
SELECT * FROM item_cat WHERE parent_id = 249
/*查询车载电器的三级菜单*/
SELECT * FROM item_cat WHERE parent_id = 281

小结: 商品分类表,通过parent_id 来指定父子级关系.

1.4 编辑ItemCatController

@RestController
@CrossOrigin
@RequestMapping("/itemCat")
public class ItemCatController {

    @Autowired
    private ItemCatService itemCatService;

    /**
     * 需求: 查询商品分类信息
     * 参数: /{level}   1一级  2 一二级  3 一二三级
     * url: /itemCat/findItemCatList/{level}  restFul
     * 返回值: SysResult(3级列表信息)
     */
    @GetMapping("findItemCatList/{level}")
    public SysResult findItemCatList(@PathVariable Integer level){

        List<ItemCat> itemCatList = itemCatService.findItemCatList(level);
        return SysResult.success(itemCatList);
    }

}

1.5 编辑ItemCatService

package com.jt.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.ItemCatMapper;
import com.jt.pojo.ItemCat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ItemCatServiceImpl implements ItemCatService{

    @Autowired
    private ItemCatMapper itemCatMapper;

    /**
     * 步骤1.查询一级菜单列表
     * @param level
     * @return
     */
    @Override
    public List<ItemCat> findItemCatList(Integer level) {
        //1.查询一级菜单
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("parent_id",0);
        List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);
        //2.查询二级菜单 二级数据是一级数据的子级 封装到一级数据中.
        for(ItemCat oneItemCat : oneList){
            int oneId = oneItemCat.getId(); //一级对象ID
            //清空原始条件  必须有
            queryWrapper.clear();
            queryWrapper.eq("parent_id",oneId);
            List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);
            for(ItemCat twoItemCat : twoList){
                //获取二级分类ID
                int twoId = twoItemCat.getId();
                //查询三级列表信息
                queryWrapper.clear();
                queryWrapper.eq("parent_id",twoId);
                List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
                //将三级列表 封装到二级对象中
                twoItemCat.setChildren(threeList);
            }
            //将二级数据封装到一级对象中
            oneItemCat.setChildren(twoList);
        }
        return oneList;
    }
}

1.6 上述案例分析

  1. 上述的案例 采用多级循环的方式. 将来会耗费服务器资源 100次 内层100次 总循环1万次. 暂时可以接受
  2. 上述的代码 频繁访问数据库.导致数据库压力增大.严重时可能导致数据库服务器宕机. 不能接受的
    优化策略: 降低数据库访问的次数

1.7 采用数据结构优化代码

思路:

  1. 用户查询所有的数据库信息. (1-2-3所有数据)
  2. 数据结构 Map<k,v> key唯一的, value可以任意类型.
    思路: Map<parentId,List>
    例子:
  3. Map<0,List<一级ItemCat对象>>
  4. Map<249,List<二级ItemCat对象>>
  5. Map<281,List<三级ItemCat对象>>
    利用map 封装父子关系.

1.8 代码具体实现

@Service
public class ItemCatServiceImpl implements ItemCatService{

    @Autowired
    private ItemCatMapper itemCatMapper;

    /**
     * 利用Map集合封装所有的数据库记录
     * 封装数据:
     *      1.遍历所有的数据信息.
     *      2.获取每一个parentId的值.
     * 例子:
     *      1.{id=1,parentId=0,name="张三"}
     *      2.{id=2,parentId=0,name="李四"}
     *      3.{id=3,parentId=1,name="王五"}
     *      Map= {
     *          key : value
     *          0   : List[张三对象,李四对象.....],
     *          1   : List[王五对象......]
     *      }
     * @return
     */
    public Map<Integer,List<ItemCat>> getMap(){
        Map<Integer,List<ItemCat>> map = new HashMap<>();
        //1.查询所有的数据库信息
        List<ItemCat> itemCatList = itemCatMapper.selectList(null);
        //2.将数据封装到map集合中
        for (ItemCat itemCat : itemCatList){
            Integer key = itemCat.getParentId(); //获取parentId当做key
            //3.判断map集合中是否有值.
            if(map.containsKey(key)){
                //有值: 获取List集合,将自己追加到其中
                map.get(key).add(itemCat);
            }else{
                //没值: 添加数据.将自己作为第一个元素填充
                List<ItemCat> list = new ArrayList<>();
                list.add(itemCat);
                map.put(key,list);
            }
        }
        return map;
    }

    @Override
    public List<ItemCat> findItemCatList(Integer level) {
        long startTime = System.currentTimeMillis();
        Map<Integer,List<ItemCat>> map = getMap();
        //根据level获取子级信息
        if(level == 1){ //只获取一级列表信息
            return map.get(0);
        }
        if(level == 2){ //获取一级和二级数据
            return getTwoList(map);
        }
        List<ItemCat> oneList = getThreeList(map);
        long endTime = System.currentTimeMillis();
        System.out.println("优化前的耗时: 500ms,优化后耗时:"+(endTime - startTime)+"ms");
        return oneList;
    }

    //获取三级列表信息  先获取1级数据,再获取2级数据.再获取3级数据

    private List<ItemCat> getThreeList(Map<Integer, List<ItemCat>> map) {
        //1.调用2级菜单方法.
        List<ItemCat> oneList = getTwoList(map);
        //2.实现思路 遍历一级集合,获取二级数据. 封装三级菜单
        for(ItemCat oneItemCat : oneList){
            //2.1 获取二级数据
            List<ItemCat> twoList = oneItemCat.getChildren();
            if(twoList == null || twoList.size()==0){
                //判断二级集合是否为null.如果为null,表示没有二级菜单.
                continue;
            }
            for (ItemCat twoItemCat : twoList){
                int twoId = twoItemCat.getId();
                List<ItemCat> threeList = map.get(twoId);
                twoItemCat.setChildren(threeList);
            }
        }
        return oneList;
    }

    //通过map集合 获取一级二级菜单信息.
    private List<ItemCat> getTwoList(Map<Integer, List<ItemCat>> map) {
        List<ItemCat> oneList = map.get(0);
        //获取二级信息,应该先遍历一级集合
        for (ItemCat oneItemCat : oneList){
            int oneId = oneItemCat.getId();
            //根据一级Id,获取二级集合
            List<ItemCat> twoList = map.get(oneId);
            oneItemCat.setChildren(twoList);
        }
        return oneList;
    }


    /**
     * 步骤1.查询一级菜单列表
     * @param level
     * @return
     */
   /* @Override
    public List<ItemCat> findItemCatList(Integer level) {
        long startTime = System.currentTimeMillis();
        //1.查询一级菜单
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("parent_id",0);
        List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);
        //2.查询二级菜单 二级数据是一级数据的子级 封装到一级数据中.
        for(ItemCat oneItemCat : oneList){
            int oneId = oneItemCat.getId(); //一级对象ID
            //清空原始条件  必须有
            queryWrapper.clear();
            queryWrapper.eq("parent_id",oneId);
            List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);
            for(ItemCat twoItemCat : twoList){
                //获取二级分类ID
                int twoId = twoItemCat.getId();
                //查询三级列表信息
                queryWrapper.clear();
                queryWrapper.eq("parent_id",twoId);
                List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
                //将三级列表 封装到二级对象中
                twoItemCat.setChildren(threeList);
            }
            //将二级数据封装到一级对象中
            oneItemCat.setChildren(twoList);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("耗时:"+ (endTime - startTime)+"ms");
        return oneList;
    }*/
}

2 商品分类新增实现

2.1 页面JS分析

  1. 页面JS分析
 		//定义商品分类新增对象
        itemCatForm: {
          name: '', //定义商品分类名称
          parentId: 0, //默认父级ID=0
          level: 1 //默认是一级菜单
        },
		
		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
        })
      },


2.2 商品分类新增接口文档

  • 请求路径: /itemCat/saveItemCat
  • 请求类型: post
  • 请求参数: 表单数据
参数名称参数说明备注
name商品分类名称不能为null
parentId用户父级ID不能为null
level分类级别1 2 3 商品分类级别
  • 返回值: SysResult对象
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

2.3 编辑ItemCatController

/**
     * 业务需求:  实现商品分类新增
     * URL:  /itemCat/saveItemCat
     * 类型: post
     * 参数: {"name":"AAAAAA","parentId":0,"level":1} json串
     * 返回值: SysResult对象
     */
    @PostMapping("/saveItemCat")
    public SysResult saveItem(@RequestBody ItemCat itemCat){

        itemCatService.saveItem(itemCat);
        return SysResult.success();
    }

2.4 编辑ItemCatService

	@Override
    @Transactional  //事务控制
    public void saveItem(ItemCat itemCat) {
        Date date = new Date();
        itemCat.setStatus(true).setCreated(date).setUpdated(date);//启动
        itemCatMapper.insert(itemCat);
    }

3 商品分类删除操作

3.1 删除业务接口

  • 请求路径: /itemCat/deleteItemCat
  • 请求类型: delete
  • 业务描述: 当删除节点为父级时,应该删除自身和所有的子节点
  • 请求参数:
参数名称参数说明备注
ID用户ID号不能为null
level商品分类级别 一级,二级,三级
  • 返回值结果 SysResult对象
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

3.2 前端页面JS

1. 页面JS
<el-button type="danger" icon="el-icon-delete" @click="deleteItemCatBtn(scope.row)">删除</el-button>


2. 发起Ajax请求
//传递分类id
        const {data: result} = await this.$http.delete("/itemCat/deleteItemCat",{params:{id:itemCat.id,level:itemCat.level}})
          if(result.status !== 200) return this.$message.error("删除商品分类失败")
          this.$message.success("删除数据成功")
          //删除成功之后,刷新页面数据
          this.findItemCatList()          

3.3 编辑ItemCatController

 /**
     * 完成商品分类的删除操作
     * 1. 编辑URL: /itemCat/deleteItemCat
     * 2. 参数: id/level
     * 3. 返回值: SysResult()
     */
    @DeleteMapping("/deleteItemCat")
    public SysResult deleteItemCat(Integer id,Integer level){

        itemCatService.deleteItemCat(id,level);
        return SysResult.success();
    }

3.4 编辑ItemCatService

//删除商品分类数据
    @Override
    public void deleteItemCat(Integer id, Integer level) {
        //判断是否为3级菜单
        if(level == 3){
            itemCatMapper.deleteById(id);
        }

        if(level == 2){
            //如果是二级,应该先获取三级数据之后删除,再删除自己
            //delete from item_cat where parent_id=#{id} or id = #{id}
            QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("parent_id",id)
                        .or()
                        .eq("id",id);
            itemCatMapper.delete(queryWrapper);
        }

        /**
         * 如何删除一级菜单?
         *  1.获取二级ID
         *  终极sql: delete from item_cat where parent_id in (twoIds)
         *          or  id in (twoIds)
         *          or  id = #{id}
         */
        if(level == 1){
            QueryWrapper<ItemCat> queryWrapper = new QueryWrapper();
            queryWrapper.eq("parent_id",id);
            List twoIds = itemCatMapper.selectObjs(queryWrapper);
            //清空数据
            queryWrapper.clear();
            //规则: 如果2级菜单有值,才会删除 2级和三级
            queryWrapper.in(twoIds.size()>0,"parent_id",twoIds)
                        .or()
                        .in(twoIds.size()>0,"id",twoIds)
                        .or()
                        .eq("id",id);
            itemCatMapper.delete(queryWrapper);
        }
    }

4 修改商品分类

4.1 状态修改操作

4.1.1 页面JS分析

1. 页面JS函数
updateStatus(scope.row)

2. 页面JS
 	  //根据ID修改状态信息
      async updateStatus(itemCat) {
        const {
          data: result
        } = await this.$http.put(`/itemCat/status/${itemCat.id}/${itemCat.status}`)
        if (result.status !== 200) return this.$message.error("修改状态失败")
        this.$message.success("状态修改成功")
      },

4.1.2 业务接口文档

  • 请求路径: /itemCat/status/{id}/{status}
    • 请求类型: put
    • 请求参数:
参数名称参数说明备注
ID用户ID号不能为null
status用户的状态信息不能为null
  • 返回值: SysResult对象
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

4.1.3 编辑ItemCatController

/**
     * 实现商品分类状态修改
     * URL: /itemCat/status/{id}/{status}
     * 请求类型: PUT/POST
     * 请求参数: id/status
     * 返回值: SysResult对象
     */
    @PutMapping("/status/{id}/{status}")
    public  SysResult updateStatus(ItemCat itemCat){

        itemCatService.updateStatus(itemCat);
        return SysResult.success();
    }

4.1.4 编辑ItemCatService

	@Override
    @Transactional
    public void updateStatus(ItemCat itemCat) {//id/status
        itemCat.setUpdated(new Date());
        itemCatMapper.updateById(itemCat);
    }

4.2 商品分类修改操作

4.2.1 页面JS分析

	1.指定修改的按钮
	<el-button type="success" icon="el-icon-edit" @click="updateItemCatBtn(scope.row)">编辑</el-button>
	
	2. 数据的回显
	//由于有层级关系,所有修改只能修改名称
      updateItemCatBtn(itemCat) {
        this.updateItemCatForm = itemCat
        this.updateItemCatDialogVisible = true
      },

	3. 修改页面的JS
	<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>
     
     4. 修改按钮的JS
       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;
      },

4.2.2 页面接口文档

  • 请求路径: /itemCat/updateItemCat
  • 请求类型: put
  • 请求参数: 表单数据 ItemCat对象
  • 返回值: SysResult对象
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

数据解析:
请添加图片描述

4.2.3 编辑ItemCatController

/**
     * 修改商品分类名称
     * URL: /itemCat/updateItemCat
     * 参数: 整个form表单  JSON串
     * 返回值: SysResult对象
     */
    @PutMapping("/updateItemCat")
    public SysResult updateItemCat(@RequestBody ItemCat itemCat){

        itemCatService.updateItemCat(itemCat);
        return SysResult.success();
    }

4.2.4 编辑ItemCatService

 //由于页面只修改的name名称.所以sql也只修改name/updated
    @Override
    @Transactional
    public void updateItemCat(ItemCat itemCat) {
        //用户只修改name,updated by id
        ItemCat temp = new ItemCat();
        temp.setId(itemCat.getId())
                .setName(itemCat.getName())
                .setUpdated(new Date());
        itemCatMapper.updateById(temp);
    }

4.3 debug断点调试

请添加图片描述

5 商品模块业务实现

5.1 商品页面跳转

  1. 编辑index.js的路由文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import ElementUI from '../components/ElementUI.vue'
import Home from '../components/Home.vue'
import User from '../components/user/user.vue'
import ItemCat from '../components/items/ItemCat.vue'
import Item from '../components/items/Item.vue'
//使用路由机制
Vue.use(VueRouter)
const routes = [
  {path: '/', redirect: '/login'},
  {path: '/login', component: Login},
  {path: '/elementUI', component: ElementUI},
  {path: '/home', component: Home, children: [
     {path: '/user', component: User},
     {path: '/itemCat', component: ItemCat},
     {path: '/item', component: Item}
  ]}
]

  1. 页面效果
    请添加图片描述

5.2 数据自动填充

5.2.1 业务分析

说明: 如果每次新增/更新时 都需要添加创建时间/修改时间 这样做比较繁琐.能否通过框架自动的实现数据填充.请添加图片描述

5.2.2 添加自动填充注解

//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;	//表示入库/更新时赋值.
}

5.2.3 配置自动填充类

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //框架用法说明: MP根据实现类,自动的完成数据的注入. MP框架自动调用
    //metaObject: 指定默认的规则
    @Override
    public void insertFill(MetaObject metaObject) {
        Date date = new Date();
        this.setFieldValByName("created", date, metaObject);
        this.setFieldValByName("updated", date, metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {

        this.setFieldValByName("updated", new Date(), metaObject);
    }
}

5.3 构建商品层级代码

5.3.1 item 表设计

请添加图片描述

5.3.2 编辑Item POJO

/**
 * @author 刘昱江
 * 时间 2021/4/7
 */
@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 上架
}

5.3.3 编辑层级代码结构

请添加图片描述

5.4 完成商品列表展现

5.4.1 页面分析

//1. 生命周期函数
 created() {
      //1.获取商品列表数据
      this.getItemList()
    },

//2. 调用 this.getItemList()
      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
      },


5.4.2 接口文档说明

  • 请求路径: /item/getItemList?query=&pageNum=1&pageSize=10
  • 请求类型: get
  • 请求参数: 使用pageResult对象接收
参数名称参数说明备注
query用户查询的数据可以为null
pageNum分页查询的页数必须赋值不能为null
pageSize分页查询的条数必须赋值不能为null
  • 返回值结果:
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据商品分页对象

5.4.3 编辑ItemController

@RestController
@CrossOrigin
@RequestMapping("/item")
public class ItemController {

    @Autowired
    private ItemService itemService;

    /**
     * 业务: 实现商品的分页查询
     * URL: /item/getItemList?query=&pageNum=1&pageSize=10
     * 参数: query=&pageNum=1&pageSize=10
     * 返回值: SysResult(PageResult)
     */
    @GetMapping("/getItemList")
    public SysResult getItemList(PageResult pageResult){//3
        //3+2(总记录数,分页结果)
        pageResult  = itemService.getItemList(pageResult);
        return SysResult.success(pageResult);//5
    }
}

5.4.4 编辑ItemService

@Service
public class ItemServiceImpl implements ItemService{

    @Autowired
    private ItemMapper itemMapper;

    /**
     *  要求: 3+2(总记录数,分页结果)
     *  关于selectPage(参数说明)
     *   参数1: page MP提供的分页对象
     *   参数2: 条件构造器
     * @param pageResult
     * @return
     */
    @Override
    public PageResult getItemList(PageResult pageResult) {
        //1.构建分页对象  参数1: 第几页   参数2: 多少条
        Page<Item> page = new Page<>(pageResult.getPageNum(),pageResult.getPageSize());
        //2.准备条件构造器 构建模糊查询
        QueryWrapper queryWrapper = new QueryWrapper();
        String query = pageResult.getQuery();
        boolean flag = StringUtils.hasLength(query);
        queryWrapper.like(flag,"title",query);

        //3.根据MP查询 实现分页数据的自动封装
        page = itemMapper.selectPage(page,queryWrapper);

        //4.获取数据,返回分页对象
        long total = page.getTotal();
        //获取分页结果
        List<Item> rows = page.getRecords();
        return pageResult.setTotal(total).setRows(rows);
    }
}

5.4.5 编辑分页配置类

@Configuration  //这是配置类
public class MybatisConfig {

    //需要通过配置文件 指定数据库类型.
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB));
        return interceptor;
    }
}

5.4.6 页面效果展现

请添加图片描述

5.5 商品状态的修改

5.5.1 页面JS分析

		<template slot-scope="scope">
            <el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949"
              @change="updateStatus(scope.row)"></el-switch>
        </template>
		
		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("更新状态成功")
      },

5.5.2 业务接口文档

  • 请求路径: /item/updateItemStatus
  • 请求类型: put
  • 请求参数: 使用对象接收
参数名称参数说明备注
id商品id不能为null
status状态信息不能为null
  • 返回值结果:
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

5.5.3 编辑ItemController

 /**
     * 修改商品的状态信息
     * URL: /item/updateItemStatus
     * 参数: JSON串 {id:xx,status:xx}
     * 返回值: SysResult对象
     */
    @PutMapping("/updateItemStatus")
    public SysResult updateItemStatus(@RequestBody Item item){

        itemService.updateItemStatus(item);
        return SysResult.success();
    }

5.5.4 编辑ItemService

 @Override
    @Transactional //控制事务
    public void updateItemStatus(Item item) {

        itemMapper.updateById(item);
    }

5.6 商品删除操作

5.6.1 页面分析

//根据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()

5.6.2 业务接口文档

  • 请求路径: /item/deleteItemById
  • 请求类型: delete
  • 请求参数:
参数名称参数说明备注
ID商品ID号不能为null
  • 返回值结果:
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

5.6.3 编辑ItemController

 /**
     * 业务需求: 根据Id 删除数据
     * URL: /item/deleteItemById
     * 参数: id
     * 返回值: SysResult对象
     */
    @DeleteMapping("/deleteItemById")
    public SysResult deleteItemById(Integer id){

        itemService.deleteItemById(id);
        return SysResult.success();
    }

5.6.4 编辑ItemService

 	@Override
    @Transactional
    public void deleteItemById(Integer id) {
    
        itemMapper.deleteById(id);
    }

5.7 商品新增操作

5.7.1 实现页面跳转

const routes = [
  {path: '/', redirect: '/login'},
  {path: '/login', component: Login},
  {path: '/elementUI', component: ElementUI},
  {path: '/home', component: Home, children: [
     {path: '/user', component: User},
     {path: '/itemCat', component: ItemCat},
     {path: '/item', component: Item},
     {path: '/item/addItem', component: AddItem}
  ]}
]

页面效果:
请添加图片描述

5.7.2 新增页面JS

表结构说明:

  1. 商品的基本信息 保存到item表
  2. 商品的详细信息 保存到item_desc表中.
 /* 添加商品按钮 */
      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 实现商品数据提交 用一个大对象 包裹2个小对象
        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")
      }

5.7.3 业务接口说明

  • 请求路径: http://localhost:8091/item/saveItem
    
  • 请求类型: post
  • 前端传递参数分析
	{
		item: {
			images: "/2021/05/20/da0c1d4781c1499399f090da8b60f359.jpg,/2021/05/20/2ac1c34776a7465887eb019655354c3c.jpg"
			itemCatId: 560
			num: "100"
			price: 718800
			sellPoint: "【华为官方直供,至高12期免息0首付,原装正品】送华为原装无线充+运动蓝牙耳机+蓝牙音箱+三合一多功能数据线+钢化膜等!"
			title: "华为P40 Pro 5G手机【12期免息可选送豪礼】全网通智能手机"
		},
		itemDesc: {
				itemDesc: "<ul><li>品牌:&nbsp;<a href=https://list.jd.com/list.html".......      "
		}
	}

  • 请求参数: 使用ItemVO对象接收
参数名称参数说明备注
itemItem商品基本信息对象封装
itemDescItemDesc商品详情信息
itemParamItemParam商品参数信息
  • ItemVO参数详解:
  • Item对象
参数名称参数类型参数说明备注
titleString商品标题信息不能为null
sellPointString商品卖点信息
priceInteger商品价格信息不能为null 需要将数据扩大100倍
numInteger商品数量信息不能为null
imagesString商品图片地址信息不能为null
itemCatIdInteger商品父级分类ID不能为null
statusBoolean商品状态信息不能为null
  • itemDesc 对象

    为了降低商品提交代码的耦合性,将大字段信息详情,采用ItemDesc对象进行封装
    
参数名称参数类型参数说明备注
idInteger商品Id信息因为Item和ItemDesc是一对一关系 所以需要依赖Item对象的Id值
itemDescString商品详情信息内部包含了大量的html语句
  • 返回值结果:
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

5.7.4 编辑ItemController

 /**
     * 完成商品新增操作
     * 1.URL地址  http://localhost:8091/item/saveItem
     * 2.参数     post   itemVO JSON串
     * 3.返回值   SysResult对象
     */
    @PostMapping("/saveItem")
    public SysResult saveItem(@RequestBody ItemVO itemVO){

        itemService.saveItem(itemVO);
        return SysResult.success();
    }

5.7.5 编辑ItemService

 @Override
    @Transactional
    public void saveItem(ItemVO itemVO) {
        Item item = itemVO.getItem();
        //设定状态
        item.setStatus(true);
        itemMapper.insert(item);
    }

6 商品文件上传

6.1 商品详情入库

6.1.1 富文本编辑器

说明: 富文本可以在页面中,实现 “所见即所得” 的效果

请添加图片描述

6.1.2 引入步骤

  1. 引入js
/* 导入富文本编辑器 */
import VueQuillEditor from 'vue-quill-editor'

/* 导入富文本编辑器对应的样式 */
import 'quill/dist/quill.core.css' // import styles
import 'quill/dist/quill.snow.css' // for snow theme
import 'quill/dist/quill.bubble.css' // for bubble theme

/* 将富文本编辑器注册为全局可用的组件 */
Vue.use(VueQuillEditor)

  1. 使用富文本编辑器
 <!-- 定义富文本编辑器-->
 <quill-editor ref="myQuillEditor" v-model="itemDesc.itemDesc">
 </quill-editor>

6.1.3 关于ItemDesc 的说明

说明: 由于Item和ItemDesc 是典型的一对一. 所以要求 item.id = itemDesc.id

@Data
@Accessors(chain = true)
@TableName("item_desc")
public class ItemDesc extends BasePojo{
    @TableId
    private Integer id;
    private String itemDesc;
}

6.1.4 编辑ItemService

 /**
     * 问题: id是主键自增. 入库之后才有主键所以
     *      应该让主键动态回显
     * 1.Mybatis 动态实现回显
     *      <insert id="xxxx" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
     *         insertinto xxxx
     *     </insert>
     * 2.MP是mybatis的增强版本.所以可以实现自动的主键回显!!!
     * @param itemVO
     */
    @Override
    @Transactional
    public void saveItem(ItemVO itemVO) {
        Item item = itemVO.getItem();
        //设定状态
        item.setStatus(true);
        itemMapper.insert(item);
        //获取商品详情
        ItemDesc itemDesc = itemVO.getItemDesc();
        itemDesc.setId(item.getId());
        itemDescMapper.insert(itemDesc);
    }

6.1.5

说明: 为了存储大字段.修改数据库类型请添加图片描述

6.2 实现商品图片上传

6.2.1 编辑页面

//1. 定义页面html
<!-- 定义商品修改的对话框 -->
    <!-- 定义商品修改的对话框 -->
    <el-dialog title="商品修改" :visible.sync="updateDialogVisible" width="60%">
      <!-- 准备修改的表单-->
      <el-form :model="updateItem" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
        <el-form-item label="标题信息" prop="title">
          <el-input v-model="updateItem.title"></el-input>
        </el-form-item>
        <el-form-item label="卖点信息" prop="sellPoint">
          <el-input v-model="updateItem.sellPoint"></el-input>
        </el-form-item>
        <el-form-item label="价格信息" prop="price">
          <el-input v-model="updateItem.price"></el-input>
        </el-form-item>
        <el-form-item label="数量信息" prop="num">
          <el-input v-model="updateItem.num"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="updateDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
      </span>
    </el-dialog>
	
	//2. 定义页面JS
	updateDialogVisible: false,
        updateItem: {},
        //准备一个校验规则
        rules: {
          title: [
                  { required: true, message: '请输入商品标题信息', trigger: 'blur' },
                  { min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
                ],
          sellPoint: [
                  { required: true, message: '请输入商品卖点信息', trigger: 'blur' },
                  { min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
                ],
          price: [
                  { required: true, message: '请输入商品价格信息', trigger: 'blur' },
                  { min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
                ],
          num: [
                  { required: true, message: '请输入商品数量信息', trigger: 'blur' },
                  { min: 3, max: 50, message: '长度在 3 到 50 个字符', trigger: 'blur' }
                ],
        }

	  //定义JS按钮
	  updateItemBtn(item){
        	console.log("扩展案例,自己实现 只需要修改 标题/卖点/价格/数量")
        	this.updateDialogVisible = true
        	this.updateItem = item
        	this.updateItem.price = (this.updateItem.price / 100).toFixed(2)
      }

6.2.2 官网说明

//1. 官网图片JS说明
  <!-- 图片上传的JS
        1. action: 代表图片上传的地址url
        2. file-list: 图片列表数据的集合[{name:"xx",url:"xxx"},{}]
        3. 钩子函数: 满足某些条件时触发.
        4. on-preview 当点击已上传列表的信息时触发
        5. on-remove  当移除列表中的图片时触发
      -->
      <el-upload
        class="upload-demo"
        action="https://jsonplaceholder.typicode.com/posts/"
        :on-preview="handlePreview"
        :on-remove="handleRemove"
        :file-list="fileList"
        list-type="picture">
        <el-button size="small" type="primary">点击上传</el-button>
        <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
      </el-upload>
2. 页面JS补充知识
   handlePreview(){
      console.log("触发查看函数!!!!")
    },
    handleRemove(){
      console.log("移除时触发!!!!")
    }

6.2.3 图片上传项目说明

<!--.文件上传组件说明
                1.action: 上传图片地址 http://localhost:8091/xxx/xxx
                2.on-preview 点击图片时触发
                3.on-remove  移除图片时触发
                4.on-success 图片上传成功时触发
                5.multiple   可以支持多张图片上传
                6.drag       是否允许拖拽
              二.请求类型:    一般上传字节信息时,首选post请求
              三.上传文件key  说明: 文件上传时的key=file.
              				 后端接收数据时采用file接收.
            -->
            <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>

//定义文件上传路径地址
uploadUrl: "http://localhost:8091/file/upload",

6.2.4 图片上传接口文档说明

  • 请求路径: http://localhost:8091/file/upload
  • 请求类型: post
  • 请求参数:
参数名称参数说明备注
file文件上传的参数名称file中携带的是二进制信息
  • 返回值结果:
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据返回ImageVO对象
  • ImageVO对象说明
参数名称参数类型参数说明备注
virtualPathString图片实际路径 不包含磁盘信息例如: 2021/11/11/a.jpg 不需要写磁盘地址
urlPathString图片url访问地址http://image.jt.com/2021/11/11/a.jpg 需要指定域名地址
fileNameString文件上传后的文件名称UUID.type

6.2.5 编辑ImageVO

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {

    private String virtualPath; //图片虚拟路径 动态的路径
    private String urlPath;  //图片回显的URL地址
    private String fileName; //文件上传后的文件名称
}

6.2.6 编辑ItemController

@RestController
@CrossOrigin
@RequestMapping("/file")
public class FileController {

    /**
     * 业务说明: 实现图片上传
     * URL: http://localhost:8091/file/upload
     * 类型: post
     * 参数: file 字节信息
     * 返回值: SysResult.success()
     * 扩展:
     *      一般情况下:
     *          一般前端向后端服务器发送字节信息.由外到内实现数据传输.
     *      采用输入流信息. InputStream file
     *          使用字节流的弊端: 1.必须手动关闭, 2.代码操作繁琐
     *          底层代码的实现.
     *       SpringMVC高级API  MultipartFile 专门处理IO流操作
     *  文件上传步骤:
     *        1.获取文件名称
     *        2.准备文件上传的目录
     *        3.判断目录是否存在  存在目录: 实现上传  没有目录:创建目录
     *        4.利用工具API方法,实现文件上传.
     *  注意事项: MultipartFile 默认支持1M的数据
     */
     @PostMapping("/upload")
     public SysResult upload(MultipartFile file) throws IOException {
        //1.获取文件名称
         String fileName = file.getOriginalFilename();
         //2.准备磁盘地址
         String dirPath = "E:/project3/images/";
         //3.将这个文件目录 封装为File对象
         File dirFile = new File(dirPath);
         //4.判断对象是否存在
         if(!dirFile.exists()){
            //如果文件目录不存在,则创建目录
             dirFile.mkdirs(); //表示多级目录上传.
         }
         //5.封装文件全路径 E:xxx/xxx/a.jpg
         String path = dirPath + fileName;
         File allFile = new File(path);
         //6.实现文件上传 将IO流按照指定的对象格式进行输出.
         file.transferTo(allFile);
         return SysResult.success();
     }
}

6.3 正则表达式(复习)

6.3.1 正则表达式说明

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
总结: 正则表达式就是一种特殊格式的字符串.校验文本信息的.

6.3.2 匹配不确定次数

请添加图片描述

6.3.3 匹配固定次数

请添加图片描述

6.3.4 匹配取值区间

请添加图片描述

6.3.5 分组匹配

请添加图片描述

6.3.6 正则案例练习

  1. 要求匹配电话号码 11位 开头都是1
    正则表达式: 1[3-9][0-9]{9}

  2. 要求匹配邮箱 xxxx@qq.com
    正则表达式:

^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$

6.4 文件上传实现

6.4.1 编辑FileController

@RestController
@CrossOrigin
@RequestMapping("/file")
public class FileController {

    @Autowired
    private FileService fileService;

    /**
     * 业务说明: 实现图片上传
     * URL: http://localhost:8091/file/upload
     * 类型: post
     * 参数: MultipartFile file 字节信息
     * 返回值: SysResult.success()
     * 问题思考:
     *      1.完成图片类型校验 jpg|png|gif....
     *      2.防止恶意程序    a.exe.jpg
     *      3.将图片分目录存储
     *             3.1.按照类型分   理论可以但是得多分配几个
     *             3.2.按照时间划分. yyyy/MM/dd
     *      4.自定义文件名称. 利用UUID充当图片名称.
     */
    @PostMapping("/upload")
    public SysResult upload(MultipartFile file) throws IOException {

        ImageVO imageVO = fileService.upload(file);
        if(imageVO == null){
            return SysResult.fail();
        }
        return SysResult.success(imageVO);
    }


    /**
     * 业务说明: 实现图片上传
     * URL: http://localhost:8091/file/upload
     * 类型: post
     * 参数:  file 字节信息
     * 返回值: SysResult.success()
     * 扩展:
     *      一般情况下:
     *          一般前端向后端服务器发送字节信息.由外到内实现数据传输.
     *      采用输入流信息. InputStream file
     *          使用字节流的弊端: 1.必须手动关闭, 2.代码操作繁琐
     *          底层代码的实现.
     *       SpringMVC高级API  MultipartFile 专门处理IO流操作
     *  文件上传步骤:
     *        1.获取文件名称
     *        2.准备文件上传的目录
     *        3.判断目录是否存在  存在目录: 实现上传  没有目录:创建目录
     *        4.利用工具API方法,实现文件上传.
     *  注意事项: MultipartFile 默认支持1M的数据
     */
     /*@PostMapping("/upload")
     public SysResult upload(MultipartFile file) throws IOException {
         //1.获取文件名称
         String fileName = file.getOriginalFilename();
         //2.准备磁盘地址
         String dirPath = "E:/project3/images/";
         //3.将这个文件目录 封装为File对象
         File dirFile = new File(dirPath);
         //4.判断对象是否存在
         if(!dirFile.exists()){
            //如果文件目录不存在,则创建目录
             dirFile.mkdirs(); //表示多级目录上传.
         }
         //5.封装文件全路径 E:xxx/xxx/a.jpg
         String path = dirPath + fileName;
         File allFile = new File(path);
         //6.实现文件上传 将IO流按照指定的对象格式进行输出.
         file.transferTo(allFile);
         return SysResult.success();
     }*/
}

6.4.2 编辑FileService

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.net.FileNameMap;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService{

    private String localDirPath = "E:/project3/images";

    //1.校验图片类型   xxx.jpg   校验后缀是否为jpg
    @Override
    public ImageVO upload(MultipartFile file) {

        //1.1 获取文件名称  abc.jpg
        String fileName = file.getOriginalFilename();
        //1.2 全部转化为小写字母
        fileName = fileName.toLowerCase();
        //1.3正则校验是否为图片类型
        if(!fileName.matches("^.+\\.(jpg|png|gif)$")){
            //图片类型 不匹配  程序应该终止
            return null;
        }

        //2.校验是否为恶意程序 怎么判断就是一张图 高度和宽度
        //2.1 通过图片对象进行处理
        try {
            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
            int height = bufferedImage.getHeight();
            int width = bufferedImage.getWidth();
            if(height == 0 || width == 0){
                return null;
            }
            //3.将图片分目录存储 yyyy/MM/dd
            String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
                                .format(new Date());
            String dateDirPath = localDirPath + dateDir;
            File dirFile = new File(dateDirPath);
            if(!dirFile.exists()){
                dirFile.mkdirs();
            }

            //4.防止文件重名  动态生成UUID.类型
            //4.1 动态生成UUID
            String uuid = UUID.randomUUID().toString()
                              .replace("-","");
            //4.2 获取图片类型        abc.jpg    .jpg
            String fileType = fileName.substring(fileName.lastIndexOf("."));
            // uuid.jpg
            String newFileName = uuid + fileType;

            //5.实现文件上传 1.准备全文件路径  2. 封装对象实现上传
            String path = dateDirPath + newFileName;
            file.transferTo(new File(path));

        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        return null;
    }
}

6.5 文件删除操作

6.5.1 文件删除JS

请添加图片描述

6.5.2 文件删除业务接口

  • 请求路径: http://localhost:8091/file/deleteFile
  • 请求类型: delete
  • 请求参数:
参数名称参数说明备注
virtualPath文件上传的虚拟的路径删除时需要磁盘路径一起删除
  • 返回值结果:
参数名称参数说明备注
status状态信息200表示服务器请求成功 201表示服务器异常
msg服务器返回的提示信息可以为null
data服务器返回的业务数据可以为null

6.5.3 编辑FileController

 /**
     * 业务说明: 文件删除操作
     * URL地址:   http://localhost:8091/file/deleteFile
     * 请求类型:   delete
     * 参数:      virtualPath 虚拟路径
     * 返回值:    SysResult对象
     */
    @DeleteMapping("/deleteFile")
    public SysResult deleteFile(String virtualPath){

        fileService.deleteFile(virtualPath);
        return SysResult.success();
    }

6.5.4 编辑FileService

@Override
    public void deleteFile(String virtualPath) {
        String filePath = localDirPath + virtualPath;
        File file = new File(filePath);
        if(file.exists()){ //如果文件存在,则删除数据
            file.delete();
        }
    }

6.6 图片路径封装

6.6.1 路径分析

  1. 图片网络地址: https://img14.360buyimg.com/n0/jfs/t2/ac4a3f32ea776da3.jpg
    协议://域名:80/虚拟地址
  2. 图片地址封装: http://image.jt.com:80/2021/11/11/uuid.jpg.

6.6.2 页面URL地址封装

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.net.FileNameMap;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService{

    private String localDirPath = "E:/project3/images";
    private String preUrl = "http://image.jt.com";

    //1.校验图片类型   xxx.jpg   校验后缀是否为jpg
    @Override
    public ImageVO upload(MultipartFile file) {

        //1.1 获取文件名称  abc.jpg
        String fileName = file.getOriginalFilename();
        //1.2 全部转化为小写字母
        fileName = fileName.toLowerCase();
        //1.3正则校验是否为图片类型
        if(!fileName.matches("^.+\\.(jpg|png|gif)$")){
            //图片类型 不匹配  程序应该终止
            return null;
        }

        //2.校验是否为恶意程序 怎么判断就是一张图 高度和宽度
        //2.1 通过图片对象进行处理
        try {
            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
            int height = bufferedImage.getHeight();
            int width = bufferedImage.getWidth();
            if(height == 0 || width == 0){
                return null;
            }
            //3.将图片分目录存储 yyyy/MM/dd
            String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
                                .format(new Date());
            String dateDirPath = localDirPath + dateDir;
            File dirFile = new File(dateDirPath);
            if(!dirFile.exists()){
                dirFile.mkdirs();
            }

            //4.防止文件重名  动态生成UUID.类型
            //4.1 动态生成UUID
            String uuid = UUID.randomUUID().toString()
                              .replace("-","");
            //4.2 获取图片类型        abc.jpg    .jpg
            String fileType = fileName.substring(fileName.lastIndexOf("."));
            // uuid.jpg
            String newFileName = uuid + fileType;

            //5.实现文件上传 1.准备全文件路径  2. 封装对象实现上传
            String path = dateDirPath + newFileName;
            file.transferTo(new File(path));

            //6. 实现ImageVO数据的返回
            //6.1 准备虚拟路径 /2021/11/11/uuid.jpg
            String virtualPath = dateDir + newFileName;
            //6.2 准备URL地址  域名前缀 + 虚拟路径
            String url =  preUrl + virtualPath;
            System.out.println(url);
            return new ImageVO(virtualPath,url,newFileName);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void deleteFile(String virtualPath) {
        String filePath = localDirPath + virtualPath;
        File file = new File(filePath);
        if(file.exists()){ //如果文件存在,则删除数据
            file.delete();
        }
    }
}

6.7动态为属性赋值

6.7.1 业务需求

说明: 如果将属性写死到java类中,后期维护时 导致维护不方便.
优化: 可以通过@value注解动态赋值.
请添加图片描述

6.7.2 编辑properties配置文件

image.localDirPath=E:/project3/images
image.preUrl=http://image.jt.com

6.7.3 属性动态赋值

请添加图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值