《尚品甄选》:后台系统——权限管理之分类和品牌管理,使用EasyExcel导入导出数据(debug一遍)
文章目录
- 一、分类管理
- 1.1 表结构介绍
- 1.2 分类列表查询
- 二、EasyExcel使用
- 2.1 EasyExcel简介
- 2.2 导出功能
- 2.3 导入功能
- 三、品牌管理
- 3.1 表结构介绍
- 3.2 列表查询
- 3.3 添加品牌
- 3.4 修改品牌
- 3.5 删除品牌
一、分类管理
分类管理就是对商品的分类数据进行维护。
1.1 表结构介绍
分类数据所对应的表结构如下所示,分类数据是具有层级结构的。
CREATE TABLE `category` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类id',
`name` varchar(50) DEFAULT NULL COMMENT '分类名称',
`image_url` varchar(200) DEFAULT NULL,
`parent_id` bigint DEFAULT NULL COMMENT '父分类id',
`status` tinyint DEFAULT NULL COMMENT '是否显示[0-不显示,1显示]',
`order_num` int DEFAULT NULL COMMENT '排序',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记(0:可用 1:不可用)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9992 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品分类'
1.2 分类列表查询
需求分析:
当页面初始化完毕以后,此时请求后端接口查询所有的一级分类数据,一级分类数据的parent_id为0。当用户点击某一个分类前的小箭头,那么此时就需要查询该分类下所对应的所有的子分类数据,是一种懒加载实现方式。
话不多说,让我们来debug一遍:首先来到controller层,拿到前端传来的第一级id值
进入业务层,根据id值从数据库中查询数据,可以看到,我这里有10条数据
下图的for循环是用来判断该分类下是否有子节点,有子节点就设置字段hasChildren为true;前端根据hasChildren的值来展示样式。
对应的两个SQL语句如下:
@Mapper
public interface CategoryMapper {
@Select("select * from category where parent_id = #{parentId} and is_deleted = 0 order by id desc")
List<Category> selectByParentId(Long parentId);
@Select("select count(*) from category where parent_id = #{id} and is_deleted = 0")
int countByParentId(Long id);
}
二、EasyExcel使用
后台管理系统是管理、处理企业业务数据的重要工具,在这样的系统中,数据的导入和导出功能是非常重要的,其主要意义包括以下几个方面:
-
提高数据操作效率:手动逐条添加或修改数据不仅费时费力,而且容易出错,此时就可以将大量数据从Excel等表格软件中导入到系统中,通过数据导入功能,可以直接将表格中的数据批量导入到系统中,提高了数据操作的效率。
-
实现数据备份与迁移:通过数据导出功能,管理员可以将系统中的数据导出为 Excel 或其他格式的文件,以实现数据备份,避免数据丢失。同时,也可以将导出的数据文件用于数据迁移或其他用途。
-
方便企业内部协作:不同部门可能会使用不同的系统或工具进行数据处理,在这种情况下,通过数据导入和导出功能,可以方便地转换和共享数据,促进企业内部协作。
2.1 EasyExcel简介
官网地址:https://easyexcel.opensource.alibaba.com/
EasyExcel 的主要特点如下:
-
高性能:EasyExcel 采用了异步导入导出的方式,并且底层使用 NIO 技术实现,使得其在导入导出大数据量时的性能非常高效。
-
易于使用:EasyExcel 提供了简单易用的 API,用户可以通过少量的代码即可实现复杂的 Excel 导入导出操作。
-
可扩展性好:EasyExcel 具有良好的扩展性,用户可以通过自定义 Converter 对自定义类型进行转换,或者通过继承 EasyExcelListener 来自定义监听器实现更加灵活的需求。
2.2 导出功能
需求说明:
当用户点击导出按钮的时候,此时将数据库中所有分类的数据导出到一个excel文件中,如图所示:
首先引入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
</dependency>
接着定义一个实体类来封装每一行的数据:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CategoryExcelVo {
@ExcelProperty(value = "id" ,index = 0)
private Long id;
@ExcelProperty(value = "名称" ,index = 1)
private String name;
@ExcelProperty(value = "图片url" ,index = 2)
private String imageUrl ;
@ExcelProperty(value = "上级id" ,index = 3)
private Long parentId;
@ExcelProperty(value = "状态" ,index = 4)
private Integer status;
@ExcelProperty(value = "排序" ,index = 5)
private Integer orderNum;
}
debug看一遍流程,来到controller层
来到业务层,首先设置响应结果类型,接着查询分类表,可以看到查询到了703条数据
数据库查询到的数据不是我们需要的数据格式,因此需要将数据库查询到的数据转换成自己定义的CategoryExcelVo类格式。
SQL语句编写如下:
@Select("select id, name, image_url, parent_id, status, order_num from category where is_deleted = 0 order by id")
List<Category> selectAll();
2.3 导入功能
需求说明:
当用户点击导入按钮的时候,此时会弹出一个对话框,让用户选择要导入的excel文件,选择完毕以后将文件上传到服务端,服务端通过easyExcel解析文件的内容,然后将解析的结果存储到category表中。如下所示:
通过EasyExcel的操作文档,对于导入功能,我们需要创建监听器类ExcelListener,让其实现ReadListener接口。
public class ExcelListener<T> implements ReadListener<T> {
/**
* 每隔100条将数据存入数据库
*/
private static final int BATCH_COUNT = 100;
/**
* 缓存的数据
*/
private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
private CategoryMapper categoryMapper;
public ExcelListener(CategoryMapper categoryMapper) {
this.categoryMapper = categoryMapper;
}
//每解析一行数据就会调用一次该方法
@Override
public void invoke(T o, AnalysisContext analysisContext) {
cachedDataList.add(o);
//达到BATCH_COUNT时,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
//存储完成,清理list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
//excel解析完毕以后需要执行的代码,这里也要保存数据,确保最后遗留的数据也存储到数据库
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
saveData();
}
//保存数据到数据库
private void saveData() {
categoryMapper.batchInsert(cachedDataList);
}
}
这里的批量插入SQL语句编写如下:
<!-- <T> void batchInsert(List<T> cachedDataList);-->
<insert id="batchInsert">
insert into category values
<foreach collection="cachedDataList" item="item" separator=",">
(#{item.id}, #{item.name}, #{item.imageUrl}, #{item.parentId},
#{item.status}, #{item.orderNum},now(), now(), 0)
</foreach>
</insert>
创建好监听器,接下来让我们debug,首先来到controller层,接收文件"01.xlsx"
来到业务层,首先创建监听器类,然后调用read方法读取excel数据。
三、品牌管理
品牌管理就是对商品所涉及到的品牌数据进行维护。
3.1 表结构介绍
CREATE TABLE `brand` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '品牌名称',
`logo` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '品牌图标',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记(0:可用 1:不可用)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='分类品牌'
3.2 列表查询
需求说明:
当品牌管理页面加载完毕以后就向后端发送分页查询请求,后端进行分页查询,返回分页结果数据。
继续debug,在controller层,接收到分页参数信息
业务层代码也很简单,分页查询品牌数据,我这里只查到了2条数据
SQL语句的编写也很容易
@Select("select * from brand where is_deleted = 0 order by id desc")
List<Brand> findByPage();
3.3 添加品牌
需求说明:
用户点击添加按钮,填写表单数据,点击提交按钮,请求后端接口完成数据的保存操作。效果如下所示:
controller层获取品牌name、logo图片地址
业务层将数据存入品牌表
SQL语句编写如下:
@Insert("insert into brand (name, logo, create_time, update_time, is_deleted)\n" +
"values (#{name}, #{logo}, now(), now(), 0)")
void save(Brand brand);
3.4 修改品牌
需求说明:
当用户点击修改按钮的时候,对话框中需要将当前行所对应的品牌数据在该表单页面进行展示。当用户在该表单中点击提交按钮的时候那么此时就需要将表单进行提交,在后端需要提交过来的表单数据修改数据库中的即可。
controller拿到修改的数据,我这里只修改了name字段
业务层根据实体类,修改品牌表。
修改操作对应的SQL语句如下:
<!-- void updateById(Brand brand);-->
<update id="updateById">
update brand set
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="logo != null and logo != ''">
logo = #{logo},
</if>
update_time = now()
where
id = #{id}
</update>
3.5 删除品牌
需求说明:
当点击删除按钮的时候此时需要弹出一个提示框,询问是否需要删除数据?如果用户点击是,那么此时向后端发送请求传递id参数,后端接收id参数进行逻辑删除。
来到controller层,获取到要删除品牌的id值
业务层也同样很简单,简单的更新语句
SQL编写如下:
@Update("update brand set is_deleted = 1,update_time = now() where id = #{id}")
void deleteById(Long id);