1 完成商品分类业务
1.1 页面JS分析
生命周期函数
created ( ) {
this . findItemCatList ( )
} ,
获取数据函数说明
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 商品分类表结构说明
表结构
sql案例练习
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;
@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;
@Override
public List< ItemCat> findItemCatList ( Integer level ) {
QueryWrapper queryWrapper = new QueryWrapper ( ) ;
queryWrapper. eq ( "parent_id" , 0 ) ;
List< ItemCat> oneList = itemCatMapper. selectList ( queryWrapper) ;
for ( ItemCat oneItemCat : oneList) {
int oneId = oneItemCat. getId ( ) ;
queryWrapper. clear ( ) ;
queryWrapper. eq ( "parent_id" , oneId) ;
List< ItemCat> twoList = itemCatMapper. selectList ( queryWrapper) ;
for ( ItemCat twoItemCat : twoList) {
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 上述案例分析
上述的案例 采用多级循环的方式. 将来会耗费服务器资源 100次 内层100次 总循环1万次. 暂时可以接受 上述的代码 频繁访问数据库.导致数据库压力增大.严重时可能导致数据库服务器宕机. 不能接受的 优化策略: 降低数据库访问的次数
1.7 采用数据结构优化代码
思路:
用户查询所有的数据库信息. (1-2-3所有数据) 数据结构 Map<k,v> key唯一的, value可以任意类型. 思路: Map<parentId,List> 例子: Map<0,List<一级ItemCat对象>> Map<249,List<二级ItemCat对象>> Map<281,List<三级ItemCat对象>> 利用map 封装父子关系.
1.8 代码具体实现
@Service
public class ItemCatServiceImpl implements ItemCatService {
@Autowired
private ItemCatMapper itemCatMapper;
public Map< Integer, List< ItemCat>> getMap ( ) {
Map< Integer, List< ItemCat>> map = new HashMap < > ( ) ;
List< ItemCat> itemCatList = itemCatMapper. selectList ( null ) ;
for ( ItemCat itemCat : itemCatList) {
Integer key = itemCat. getParentId ( ) ;
if ( map. containsKey ( key) ) {
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 ( ) ;
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;
}
private List< ItemCat> getThreeList ( Map< Integer, List< ItemCat>> map ) {
List< ItemCat> oneList = getTwoList ( map) ;
for ( ItemCat oneItemCat : oneList) {
List< ItemCat> twoList = oneItemCat. getChildren ( ) ;
if ( twoList == null || twoList. size ( ) == 0 ) {
continue ;
}
for ( ItemCat twoItemCat : twoList) {
int twoId = twoItemCat. getId ( ) ;
List< ItemCat> threeList = map. get ( twoId) ;
twoItemCat. setChildren ( threeList) ;
}
}
return oneList;
}
private List< ItemCat> getTwoList ( Map< Integer, List< ItemCat>> map ) {
List< ItemCat> oneList = map. get ( 0 ) ;
for ( ItemCat oneItemCat : oneList) {
int oneId = oneItemCat. getId ( ) ;
List< ItemCat> twoList = map. get ( oneId) ;
oneItemCat. setChildren ( twoList) ;
}
return oneList;
}
}
2 商品分类新增实现
2.1 页面JS分析
页面JS分析
itemCatForm: {
name: '' ,
parentId: 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 商品分类级别
参数名称 参数说明 备注 status 状态信息 200表示服务器请求成功 201表示服务器异常 msg 服务器返回的提示信息 可以为null data 服务器返回的业务数据 可以为null
2.3 编辑ItemCatController
@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 商品分类级别 一级,二级,三级
参数名称 参数说明 备注 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请求
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
@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 ) {
if ( level == 3 ) {
itemCatMapper. deleteById ( id) ;
}
if ( level == 2 ) {
QueryWrapper< ItemCat> queryWrapper = new QueryWrapper < > ( ) ;
queryWrapper. eq ( "parent_id" , id)
. or ( )
. eq ( "id" , id) ;
itemCatMapper. delete ( queryWrapper) ;
}
if ( level == 1 ) {
QueryWrapper< ItemCat> queryWrapper = new QueryWrapper ( ) ;
queryWrapper. eq ( "parent_id" , id) ;
List twoIds = itemCatMapper. selectObjs ( queryWrapper) ;
queryWrapper. clear ( ) ;
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
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}
参数名称 参数说明 备注 ID 用户ID号 不能为null status 用户的状态信息 不能为null
参数名称 参数说明 备注 status 状态信息 200表示服务器请求成功 201表示服务器异常 msg 服务器返回的提示信息 可以为null data 服务器返回的业务数据 可以为null
4.1.3 编辑ItemCatController
@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 ) {
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
@PutMapping ( "/updateItemCat" )
public SysResult updateItemCat ( @RequestBody ItemCat itemCat ) {
itemCatService. updateItemCat ( itemCat) ;
return SysResult. success ( ) ;
}
4.2.4 编辑ItemCatService
@Override
@Transactional
public void updateItemCat ( ItemCat itemCat ) {
ItemCat temp = new ItemCat ( ) ;
temp. setId ( itemCat. getId ( ) )
. setName ( itemCat. getName ( ) )
. setUpdated ( new Date ( ) ) ;
itemCatMapper. updateById ( temp) ;
}
4.3 debug断点调试
5 商品模块业务实现
5.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}
] }
]
页面效果
5.2 数据自动填充
5.2.1 业务分析
说明: 如果每次新增/更新时 都需要添加创建时间/修改时间 这样做比较繁琐.能否通过框架自动的实现数据填充.
5.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 {
@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
@Data
@Accessors ( chain = true )
@TableName ( "item" )
public class Item extends BasePojo {
@TableId ( type= IdType. AUTO )
private Integer id;
private String title;
private String sellPoint;
private Integer price;
private Integer num;
private String images;
private Integer itemCatId;
private Boolean status;
}
5.3.3 编辑层级代码结构
5.4 完成商品列表展现
5.4.1 页面分析
created ( ) {
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;
@GetMapping ( "/getItemList" )
public SysResult getItemList ( PageResult pageResult ) {
pageResult = itemService. getItemList ( pageResult) ;
return SysResult. success ( pageResult) ;
}
}
5.4.4 编辑ItemService
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemMapper itemMapper;
@Override
public PageResult getItemList ( PageResult pageResult ) {
Page< Item> page = new Page < > ( pageResult. getPageNum ( ) , pageResult. getPageSize ( ) ) ;
QueryWrapper queryWrapper = new QueryWrapper ( ) ;
String query = pageResult. getQuery ( ) ;
boolean flag = StringUtils. hasLength ( query) ;
queryWrapper. like ( flag, "title" , query) ;
page = itemMapper. selectPage ( page, queryWrapper) ;
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
@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 页面分析
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 请求参数:
参数名称 参数说明 备注 status 状态信息 200表示服务器请求成功 201表示服务器异常 msg 服务器返回的提示信息 可以为null data 服务器返回的业务数据 可以为null
5.6.3 编辑ItemController
@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
表结构说明:
商品的基本信息 保存到item表 商品的详细信息 保存到item_desc表中.
async addItemBtn ( ) {
this . $refs. addItemFormRef. validate ( valid => {
if ( ! valid) return this . $message. error ( "请输入商品必填项" )
} )
this . addItemForm. price = this . addItemForm. price * 100
this . addItemForm. images = this . addItemForm. images. join ( "," )
let submitAddItem = {
item : this . addItemForm,
itemDesc: this . itemDesc
}
let { data: result} = await this . $http. post ( "/item/saveItem" , submitAddItem)
if ( result. status !== 200 ) return this . $message. error ( "商品添加失败" )
this . $message. success ( "商品添加成功" )
this . $router. push ( "/item" )
}
5.7.3 业务接口说明
{
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>品牌: <a href=https://list.jd.com/list.html" ... ... . "
}
}
参数名称 参数说明 备注 item Item 商品基本信息对象封装 itemDesc ItemDesc 商品详情信息 itemParam ItemParam 商品参数信息
参数名称 参数类型 参数说明 备注 title String 商品标题信息 不能为null sellPoint String 商品卖点信息 price Integer 商品价格信息 不能为null 需要将数据扩大100倍 num Integer 商品数量信息 不能为null images String 商品图片地址信息 不能为null itemCatId Integer 商品父级分类ID 不能为null status Boolean 商品状态信息 不能为null
参数名称 参数类型 参数说明 备注 id Integer 商品Id信息 因为Item和ItemDesc是一对一关系 所以需要依赖Item对象的Id值 itemDesc String 商品详情信息 内部包含了大量的html语句
参数名称 参数说明 备注 status 状态信息 200表示服务器请求成功 201表示服务器异常 msg 服务器返回的提示信息 可以为null data 服务器返回的业务数据 可以为null
5.7.4 编辑ItemController
@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 引入步骤
引入js
import VueQuillEditor from 'vue-quill-editor'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue. use ( VueQuillEditor)
使用富文本编辑器
< ! -- 定义富文本编辑器-- >
< 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
@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 编辑页面
< ! -- 定义商品修改的对话框 -- >
< ! -- 定义商品修改的对话框 -- >
< 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>
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' }
] ,
}
updateItemBtn ( item ) {
console. log ( "扩展案例,自己实现 只需要修改 标题/卖点/价格/数量" )
this . updateDialogVisible = true
this . updateItem = item
this . updateItem. price = ( this . updateItem. price / 100 ) . toFixed ( 2 )
}
6.2.2 官网说明
< ! -- 图片上传的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文件,且不超过500 kb< / 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文件,且不超过500 kb< / 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对象
参数名称 参数类型 参数说明 备注 virtualPath String 图片实际路径 不包含磁盘信息 例如: 2021/11/11/a.jpg 不需要写磁盘地址 urlPath String 图片url访问地址 http://image.jt.com/2021/11/11/a.jpg 需要指定域名地址 fileName String 文件上传后的文件名称 UUID.type
6.2.5 编辑ImageVO
@Data
@Accessors ( chain = true )
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {
private String virtualPath;
private String urlPath;
private String fileName;
}
6.2.6 编辑ItemController
@RestController
@CrossOrigin
@RequestMapping ( "/file" )
public class FileController {
@PostMapping ( "/upload" )
public SysResult upload ( MultipartFile file) throws IOException {
String fileName = file. getOriginalFilename ( ) ;
String dirPath = "E:/project3/images/" ;
File dirFile = new File ( dirPath) ;
if ( ! dirFile. exists ( ) ) {
dirFile. mkdirs ( ) ;
}
String path = dirPath + fileName;
File allFile = new File ( path) ;
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 正则案例练习
要求匹配电话号码 11位 开头都是1 正则表达式: 1[3-9][0-9]{9}
要求匹配邮箱 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;
@PostMapping ( "/upload" )
public SysResult upload ( MultipartFile file) throws IOException {
ImageVO imageVO = fileService. upload ( file) ;
if ( imageVO == null ) {
return SysResult. fail ( ) ;
}
return SysResult. success ( imageVO) ;
}
}
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" ;
@Override
public ImageVO upload ( MultipartFile file ) {
String fileName = file. getOriginalFilename ( ) ;
fileName = fileName. 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 ;
}
String dateDir = new SimpleDateFormat ( "/yyyy/MM/dd/" )
. format ( new Date ( ) ) ;
String dateDirPath = localDirPath + dateDir;
File dirFile = new File ( dateDirPath) ;
if ( ! dirFile. exists ( ) ) {
dirFile. mkdirs ( ) ;
}
String uuid = UUID . randomUUID ( ) . toString ( )
. replace ( "-" , "" ) ;
String fileType = fileName. substring ( fileName. lastIndexOf ( "." ) ) ;
String newFileName = uuid + fileType;
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
@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 路径分析
图片网络地址: https://img14.360buyimg.com/n0/jfs/t2/ac4a3f32ea776da3.jpg 协议://域名:80/虚拟地址 图片地址封装: 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" ;
@Override
public ImageVO upload ( MultipartFile file ) {
String fileName = file. getOriginalFilename ( ) ;
fileName = fileName. 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 ;
}
String dateDir = new SimpleDateFormat ( "/yyyy/MM/dd/" )
. format ( new Date ( ) ) ;
String dateDirPath = localDirPath + dateDir;
File dirFile = new File ( dateDirPath) ;
if ( ! dirFile. exists ( ) ) {
dirFile. mkdirs ( ) ;
}
String uuid = UUID . randomUUID ( ) . toString ( )
. replace ( "-" , "" ) ;
String fileType = fileName. substring ( fileName. lastIndexOf ( "." ) ) ;
String newFileName = uuid + fileType;
String path = dateDirPath + newFileName;
file. transferTo ( new File ( path) ) ;
String virtualPath = dateDir + newFileName;
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 属性动态赋值