商品模块的完善
目录
前言
继续
提示:以下是本篇文章正文内容,下面案例可供参考
一、商品分类实现
1.1 层级代码搭建
1.1.1 item_cat表设计
通过parent_id 实现父子关系的查询

1.1.2 编辑POJO ItemCat

1.1.3 编辑ItemCatMapper
说明: 编辑完成Mapper之后,自己编辑Service/Controller 自行注入.

1.2 查询3级商品分类信息
- 请求路径: /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.3.1 编辑ItemCatController
@RestController @CrossOrigin @RequestMapping("/itemCat") public class ItemCatController { @Autowired private ItemCatService itemCatService; /** * 请求路径: /itemCat/findItemCatList/{level} * 请求类型: get * 请求参数: level * 返回值: SysResult(List集合) */ @GetMapping("/findItemCatList/{level}") public SysResult findItemCatList(@PathVariable Integer level){ List list = itemCatService.findItemCatList(level); return SysResult.success(list); } } 1.3.2 编辑ItemCatService
1. 编辑ItemCatService接口
public interface ItemCatService { List findItemCatList(Integer level); } 2. 编辑ItemCatServiceImpl
@Service public class ItemCatServiceImpl implements ItemCatService{ @Autowired private ItemCatMapper itemCatMapper; /** * Map> * 0,一级菜单集合 * 一级Id, 二级菜单集合 * 二级Id, 三级菜单集合 * 业务思路: * 判断是否已经存在parentId * 不存在: 我是第一个元素 封装到list中 之后保存到Map中 * 存在: 获取List集合,将自己追加到其中 * @return * 扩展知识: map每次都需要查询数据库,如果采用redis缓存,则性能极大的提升 2ms完成查询 */ public Map> getMap(){ //1.查询全部数据库记录 List list = itemCatMapper.selectList(null); //2.将list集合数据,封装到Map集合中 Map> map = new HashMap<>(); for (ItemCat itemCat : list){ //遍历所有的数据 int parentId = itemCat.getParentId(); if(map.containsKey(parentId)){ //key存在,将数据追加即可 map.get(parentId).add(itemCat); }else{ //key不存在 我是当前parentId的第一个子级 List temp = new ArrayList<>(); temp.add(itemCat); map.put(parentId,temp); } } return map; } //要求20毫秒 实现查询 查询一次数据库 代码的魅力! //Map子级> @Override public List findItemCatList(Integer level) { long startTime = System.currentTimeMillis(); //map集合相当于数据库 Map> map = getMap(); if(level == 1){ return map.get(0); } if(level == 2){ //查询一级和二级 return getTwoList(map); } List list = getThreeList(map); long endTime = System.currentTimeMillis(); System.out.println(endTime - startTime+"毫秒!!!!!"); return list; } /** * 获取一级/二级/三级数据 * @param map * @return */ private List getThreeList(Map> map) { //1.获取一级和二级 List oneList = getTwoList(map); //一级数据不可能为null //2.遍历一级集合 获取二级的数据 for (ItemCat oneItemCat :oneList){ //二级数据可能为null List twoList = oneItemCat.getChildren(); if(twoList == null || twoList.size()==0){ //表示数据没有二级 本次循环应该终止,开始下一次循环 continue; } //二级列表一定有值,可以查询三级列表 for (ItemCat twoItemCat : twoList){ //获取二级Id.查询三级数据 int parentId = twoItemCat.getId(); List threeList = map.get(parentId); //将三级保存到二级数据中 twoItemCat.setChildren(threeList); } } return oneList; } private List getTwoList(Map> map) { //1.获取一级菜单 List oneList = map.get(0); //2.遍历数据 for (ItemCat oneItemCat : oneList){ //key int parentId = oneItemCat.getId(); //根据父级查询子级 List twoList = map.get(parentId); //封装子级数据 oneItemCat.setChildren(twoList); } return oneList; } //只查询一级商品分类 400毫秒 /* @Override public List findItemCatList(Integer level) { long startTime = System.currentTimeMillis(); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("parent_id",0); //查询一级 List oneList = itemCatMapper.selectList(queryWrapper); for (ItemCat oneItemCat : oneList){ //10条 //清空历史条件 queryWrapper.clear(); queryWrapper.eq("parent_id",oneItemCat.getId()); //查询二级数据 List twoList = itemCatMapper.selectList(queryWrapper); for (ItemCat twoItemCat : twoList){ //10条 queryWrapper.clear(); queryWrapper.eq("parent_id",twoItemCat.getId()); //查询三级数据 List threeList = itemCatMapper.selectList(queryWrapper); twoItemCat.setChildren(threeList); } oneItemCat.setChildren(twoList); } long endTime = System.currentTimeMillis(); System.out.println(endTime-startTime+"毫秒"); return oneList; }*/ } 1.3.3 页面效果展现

1.4 商品分类状态修改
1.4.1 接口文档
- 请求路径: /itemCat/status/{id}/{status}
- 请求类型: put
- 请求参数:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| id | 用户ID值 | 不能为null |
| status | 商品状态信息 | 不能为null |
- 返回值: SysResult对象
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 可以为null |
1.4.2 编辑ItemCatController
/** * - 请求路径: /itemCat/status * - 请求类型: put * - 返回值: SysResult对象 */ @PutMapping("/status/{id}/{status}") public SysResult updateStatus(ItemCat itemCat){ itemCatService.updateStatus(itemCat); return SysResult.success(); } 1.4.3 编辑ItemCatService
1. 编辑ItemCatService接口
public interface ItemCatService { List findItemCatList(Integer level); void updateStatus(ItemCat itemCat); } 2.编辑ItemCatServiceImpl实现类
//MP原则: 对象操作数据库,根据对象中不为null的属性进行操作 @Override @Transactional //事务控制 public void updateStatus(ItemCat itemCat) { itemCat.setUpdated(new Date()); //可以被优化!!! //update user set status=xx,updated=xx where id=xx itemCatMapper.updateById(itemCat); } 1.5 MP数据自动填充功能
1.5.1 编辑BasePOJO

1.5.2 编辑配置类
package com.jt.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; @Component public class MyMetaObjectHandler implements MetaObjectHandler { //优势: 以后操作数据表无需手动操作时间!!! 都会自动填充 @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); } } 1.6 商品分类新增
1.6.1 业务接口文档
- 请求路径: /itemCat/saveItemCat
- 请求类型: post
- 请求参数: 表单数据
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| name | 商品分类名称 | 不能为null |
| parentId | 分类父级ID | 不能为null |
| level | 分类级别 | 1 2 3 商品分类级别 |
- 返回值: SysResult对象
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 可以为null |
1.6.2 编辑ItemCatController
/** * 实现商品分类新增 * - 请求路径: /itemCat/saveItemCat * - 请求类型: post * - 请求参数: 表单数据 * - 返回值结果: SysResult对象 */ @PostMapping("/saveItemCat") public SysResult saveItemCat(@RequestBody ItemCat itemCat){ itemCatService.saveItemCat(itemCat); return SysResult.success(); } 1.6.3 编辑ItemCatService
1. 编辑ItemCatService接口
void saveItemCat(ItemCat itemCat); 2. 编辑ItemCatServiceImpl
@Override @Transactional public void saveItemCat(ItemCat itemCat) { itemCat.setStatus(true); itemCatMapper.insert(itemCat); } 1.7 商品分类修改操作
1.7.1 业务接口文档
- 请求路径: /itemCat/updateItemCat
- 请求类型: put
- 请求参数: 表单数据 ItemCat对象
- 返回值: SysResult对象
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 可以为null |
1.7.2 编辑ItemCatController
/** * - 请求路径: /itemCat/updateItemCat * - 请求类型: put * - 请求参数: 表单数据 ItemCat对象 * - 返回值: SysResult对象 */ @PutMapping("/updateItemCat") public SysResult updateItemCat(@RequestBody ItemCat itemCat){ itemCatService.updateItemCat(itemCat); return SysResult.success(); } 1.7.3 编辑ItemCatService
1. 编辑ItemCatService
void updateItemCat(ItemCat itemCat); 2. 编辑ItemCatServiceImpl
@Override @Transactional //其中必定有ID 及修改后的name名称 public void updateItemCat(ItemCat itemCat) { //修改时间,自动填充 itemCatMapper.updateById(itemCat); } 1.8 商品分类删除
1.8.1 业务接口说明
- 请求路径: /itemCat/deleteItemCat
- 请求类型: delete
- 业务描述: 当删除节点为父级时,应该删除自身和所有的子节点
- 请求参数:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| id | 商品分类id号 | 不能为null |
| level | 商品分类级别 一级,二级,三级 |
- 返回值结果 SysResult对象
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 可以为null |
1.8.2 编辑ItemCatController
/** * - 请求路径: /itemCat/deleteItemCat?id=xx&level=xx * - 请求类型: delete * - 业务描述: 当删除节点为父级时,应该删除自身和所有的子节点 * - 请求参数: id/level * - 返回值: SysResult对象 */ @DeleteMapping("/deleteItemCat") public SysResult deleteItemCat(ItemCat itemCat){ itemCatService.deleteItemCat(itemCat); return SysResult.success(); } 1.8.3 编辑ItemCatService
1. 编辑Service接口
void deleteItemCat(ItemCat itemCat); 2. 编辑ServiceImpl实现类
/** * 要求: 高效的删除!!! * 策略: * 1.如果level=3 则可以直接删除 * 2.如果level=2 先查询是否有3级, 如果有直接删除,没有只删除2级 * 3.如果level=1 先查询2级,再查询3级. 先删除3级,再删除2级,再删除一级 * @param itemCat */ @Override @Transactional public void deleteItemCat(ItemCat itemCat) { //1.先删除3级 if(itemCat.getLevel() == 3){ itemCatMapper.deleteById(itemCat.getId()); } //2.sql where parent_id=xx or id=xx if(itemCat.getLevel() == 2){ int parentId = itemCat.getId(); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("parent_id",parentId) .or() .eq("id",itemCat.getId()); itemCatMapper.delete(queryWrapper); } //3.完成3级菜单的删除 核心是二级菜单 if(itemCat.getLevel() == 1){//扩展问题: 如何高效的删除!!! int oneId = itemCat.getId(); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("parent_id", oneId); //获取二级ID List twoIds = itemCatMapper.selectObjs(queryWrapper); //通过二级ID 删除三级数据 //where parent_id in twoIds or id in twoIds or id = oneId queryWrapper.clear(); queryWrapper.in(twoIds !=null && twoIds.size()>0 ,"parent_id",twoIds) .or() .in(twoIds !=null && twoIds.size()>0 ,"id",twoIds) .or() .eq("id",oneId); itemCatMapper.delete(queryWrapper); } } 2. 商品模块实现
2.1 表设计
1. 修改表字段
说明: 将item_desc中的表字段 数据类型扩大mediumText .

2. item表 商品基本表

3. item_desc表_详情信息

4. item表与itemDesc表说明
表关系: 一对一 item.id = item_desc.id
2.2 Item和ItemDesc POJO说明
2.2.1 编辑Item

2.2.2 编辑ItemDesc对象

2.3 商品列表展现
2.3.1 业务接口文档说明
- 请求路径: /item/getItemList?query=&pageNum=1&pageSize=10
- 请求类型: get
- 请求参数: 使用pageResult对象接收
| 参数名称 | 参数说明 | 备注信息 |
|---|---|---|
| query | 用户查询的数据 | 可以为null |
| pageNum | 分页查询的页数 | 必须赋值不能为null |
| pageSize | 分页查询的条数 | 必须赋值不能为null |
- 返回值结果:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 商品分页对象 |
2.3.2 编辑ItemController
@RestController @CrossOrigin @RequestMapping("/item") public class ItemController { @Autowired private ItemService itemService; /** * 请求路径: /item/getItemList?query=&pageNum=1&pageSize=10 * 请求类型: get * 请求参数: 使用pageResult对象接收 * 返回值: SysResult对象(pageResult) */ @GetMapping("/getItemList") public SysResult getItemList(PageResult pageResult){//3个 pageResult = itemService.getItemList(pageResult);//+2操作 return SysResult.success(pageResult); //5个 } } 2.3.3 编辑ItemService
1. 编辑ItemService
public interface ItemService { PageResult getItemList(PageResult pageResult); }
2. 编辑ItemServiceImpl
@Service public class ItemServiceImpl implements ItemService{ @Autowired private ItemMapper itemMapper; @Autowired private ItemDescMapper itemDescMapper; /** * 分页: * 1.Sql写法 特点:针对专门的数据库开发mysql,Oracle,DB2 速度快 * 2.MP 写法 特点: 可以自行的切换数据库.MP自动根据数据库类型生成Sql 速度慢 * @param pageResult * @return */ @Override public PageResult getItemList(PageResult pageResult) { //1.用户查询的where条件 QueryWrapper- queryWrapper = new QueryWrapper<>(); boolean flag = StringUtils.hasLength(pageResult.getQuery()); queryWrapper.like(flag,"title", pageResult.getQuery()); //2.page是MP分页对象 参数1:页数 参数2:条数 Page
- page = new Page<>(pageResult.getPageNum(),pageResult.getPageSize());//2个参数 //MP在内部自动的获取 总数和分页后的结果 page = itemMapper.selectPage(page,queryWrapper);//4个参数 2+2的操作 //3.获取数据之后封装 long total = page.getTotal(); List
- rows = page.getRecords(); return pageResult.setTotal(total).setRows(rows); } }
2.3.4 编辑分页配置类
@Configuration //添加配置类 public class MybatisPlusConfig { // 最新版 // 核心功能: 指定数据库版本,自动生成Sql @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MARIADB)); return interceptor; } } 2.4 商品状态修改
2.4.1 业务接口文档
- 请求路径: /item/updateItemStatus
- 请求类型: put
- 请求参数: 使用对象接收
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| id | 商品id | 不能为null |
| status | 状态信息 | 不能为null |
- 返回值结果:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 可以为null |
2.4.1 编辑ItemController
/** * 实现商品状态修改 * - 请求路径: /item/updateItemStatus * - 请求类型: put * - 请求参数: 使用对象接收 id/status * - 返回值: SysResult对象 JSON串 */ @PutMapping("/updateItemStatus") public SysResult updateItemStatus(@RequestBody Item item){ itemService.updateItemStatus(item); return SysResult.success(); } 2.4.3 编辑ItemService
1. 编辑接口
void updateItemStatus(Item item); 2. 编辑实现类
@Override @Transactional //事务注解 public void updateItemStatus(Item item) { itemMapper.updateById(item); } 2.5 商品删除操作
2.5.1 编辑业务接口
- 请求路径: /item/deleteItemById
- 请求类型: delete
- 请求参数:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| id | 商品id | 不能为null |
- 返回值结果:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 可以为null |
2.5.2 编辑ItemController
/** * 完成商品删除操作 * - 请求路径: /item/deleteItemById?id=xx * - 请求类型: delete/get * - 请求参数: id=xxx * - 返回值: SysResult对象 */ @DeleteMapping("/deleteItemById") public SysResult deleteItemById(Integer id){ itemService.deleteItemById(id); return SysResult.success(); } 2.5.3 编辑ItemService
1. 编辑ItemService接口
void deleteItemById(Integer id); 2. 编辑ItemServiceImpl
//item表/itemDesc表 一对一 @Override @Transactional public void deleteItemById(Integer id) { itemMapper.deleteById(id); itemDescMapper.deleteById(id); } 2.6 商品新增实现
2.6.1 路由跳转
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 Item from '../components/items/Item.vue' import ItemCat from '../components/items/ItemCat.vue' import AddItem from '../components/items/addItem.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: '/item', component: Item}, {path: '/itemCat', component: ItemCat}, {path: '/item/addItem', component: AddItem} ]}, ] 2.6.2 商品新增业务接口
- 请求路径: 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: " - 请求参数: 使用ItemVO对象接收
| 参数名称 | 参数类型 | 参数说明 | 备注 |
|---|---|---|---|
| item | Item | 商品基本信息对象封装 | 不能为null |
| itemDesc | ItemDesc | 商品详情信息 | 不能为null |
- ItemVO参数详解:
- Item对象
| 参数名称 | 参数类型 | 参数说明 | 备注 |
|---|---|---|---|
| title | String | 商品标题信息 | 不能为null |
| sellPoint | String | 商品卖点信息 | 不能为null |
| price | Integer | 商品价格信息 | 不能为null 需要将数据扩大100倍 |
| num | Integer | 商品数量信息 | 不能为null |
| images | String | 商品图片地址信息 | 不能为null |
| itemCatId | Integer | 商品父级分类ID | 不能为null |
| status | Boolean | 商品状态信息 | 不能为null |
- itemDesc 对象
- 为了降低商品提交代码的耦合性,将大字段信息详情,采用ItemDesc对象进行封装
| 参数名称 | 参数类型 | 参数说明 | 备注 |
|---|---|---|---|
| id | Integer | 商品Id信息 | 因为Item和ItemDesc是一对一关系 所以需要依赖Item对象的Id值 |
| itemDesc | String | 商品详情信息 | 内部包含了大量的html语句 |
- 返回值结果:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 可以为null |
2.6.3 编辑ItemController
/** * - 请求路径: http://localhost:8091/item/saveItem * - 请求类型: post * - 前端传递参数分析 使用ItemVO对象接收 JSON * - 返回值: SysResult对象 */ @PostMapping("/saveItem") public SysResult saveItem(@RequestBody ItemVO itemVO){ itemService.saveItem(itemVO); return SysResult.success(); } 2.6.4 编辑ItemService
1. 编辑ItemService接口
void saveItem(ItemVO itemVO); 2. 编辑ItemServiceImpl实现类
/** * 难点: 数据如何回显 * 1.useGeneratedKeys="true" keyColumn="字段" keyProperty="属性名" * 2.MP自动将数据进行回显 */ @Override @Transactional public void saveItem(ItemVO itemVO) { //1.入库商品表 Item item = itemVO.getItem(); item.setStatus(true); //ID主键自增,入库之后才会有ID,要求Id自动回显!!! itemMapper.insert(item); //2.商品入库操作 ItemDesc itemDesc = itemVO.getItemDesc(); itemDesc.setId(item.getId()); itemDescMapper.insert(itemDesc); } 2.7 商品图片上传
2.7.1 文件上传业务接口
知识回顾: GET请求类型 支持最大的上传量2K(不同的浏览器支持不一样 最大),所以一般上传操作使用POST请求.
- 请求路径: http://localhost:8091/file/upload
- 请求类型: post
- 请求参数:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| file | 文件上传的参数名称 | file中携带的是二进制信息 |
- 返回值结果:
| 参数名称 | 参数说明 | 备注 |
|---|---|---|
| status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
| msg | 服务器返回的提示信息 | 可以为null |
| data | 服务器返回的业务数据 | 返回ImageVO对象 |
- ImageVO对象说明
| 参数名称 | 参数类型 | 参数说明 | 备注 |
|---|---|---|---|
| virtualPath | String | 图片实际路径 不包含磁盘信息 | 例如: 2021/11/11/a.jpg 不需要写磁盘地址 |
| urlPath | String | 图片url访问地址 | http://image.jt.com/2021/11/11/a.jpg 需要指定域名地址 |
| fileName | String | 文件上传后的文件名称 | UUID.type |
2.7.2 编辑ImageVO
@Data @Accessors(chain = true) @NoArgsConstructor @AllArgsConstructor public class ImageVO { private String virtualPath; //动态变化的路径 private String urlPath; //网络地址 private String fileName; //图片名称 uuid.jpg } 2.7.3 编辑FileController
package com.jt.controller; import com.jt.service.FileService; import com.jt.vo.SysResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.io.InputStream; @RestController @RequestMapping("/file") @CrossOrigin public class FileController { @Autowired private FileService fileService; /** * - 请求路径: http://localhost:8091/file/upload * - 请求类型: post * - 请求参数: file: 二进制的字节信息 * - 返回值: SysResult对象(ImageVO) * 核心API: * file.transferTo("图片的全路径"); */ @PostMapping("/upload") public SysResult upload(MultipartFile file) throws IOException { ImageVO imageVO = fileService.upload(file); if(imageVO == null){ return SysResult.fail(); } return SysResult.success(imageVO); } } 2.7.5 编辑FileService
1. 编辑FileService接口
public interface FileService { ImageVO upload(MultipartFile file); } 2. 编辑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{ //定义根目录 windows系统采用该目录 Linux系统需要切换目录 private String preFilePath = "D:/JT-SOFT/image"; //定义网络地址前缀 private String preURLPath = "http://image.jt.com"; /** * 业务思路: * 1.校验图片的类型 jpg|png|gif * 2.校验是否为恶意程序 木马.exe.jpg * 3.将图片进行分目录存储 hash方式存储|时间格式存储 * 4.防止图片重名,使用UUID. * @param file * @return */ @Override public ImageVO upload(MultipartFile file) { //第一步: 校验图片类型 //1.获取文件名称 abc.JPG //2.bug: 文件名称大小写问题 全部转化为小写 String fileName = file.getOriginalFilename().toLowerCase(); if(!fileName.matches("^.+\\.(jpg|png|gif)$")){ //如果图片不满足条件,则程序终止 return null; } //第二步: 校验是否为恶意程序 try { BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); int height = bufferedImage.getHeight(); int width = bufferedImage.getWidth(); if(height==0 || width==0){ return null; } //第三步: 分目录存储 提高检索的效率 按照时间将目录划分 /yyyy/MM/dd/ String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date()); // D:/JT-SOFT/image2022/01/10 String fileDir = preFilePath + datePath; //创建目录 File dirFile = new File(fileDir); if(!dirFile.exists()){//目录没有的时候,应该创建目录 dirFile.mkdirs(); } //第四步: 防止文件重名 String uuid = UUID.randomUUID().toString().replace("-",""); int index = fileName.lastIndexOf("."); //获取数据 .jpg String fileType = fileName.substring(index); //新文件名称 fileName = uuid + fileType; //第五步: 实现文件上传 // D:/JT-SOFT/image/2022/01/10/uuid.jpg String filePath = fileDir + fileName; file.transferTo(new File(filePath)); //第六步: 封装ImageVO返回数据 /2022/01/10/uuid.jpg String virtualPath = datePath + fileName; //第七步: 封装网络地址 http://image.jt.com/2022/01/10/uuid.jpg String urlPath = preURLPath + virtualPath; System.out.println(urlPath); return new ImageVO(virtualPath,urlPath,fileName); } catch (IOException e) { e.printStackTrace(); return null; } } } 2.8 商品图片删除操作
2.8.1 接口文档
管理员