目录:
(1)EasyExcel-写操作
(2)EasyExcel-读操作
(3)后台系统-数据字典-导出
(4) 后台系统-数据字典-导入
(1)EasyExcel-写操作
往数据字典里面写数据,可以通过先把数据写到Excel表格里面,然后再导入进去,需要用到第三方技术来实现,操作excel表格
- EasyExcel介绍
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
文档地址:https://alibaba-easyexcel.github.io/index.html
github地址:GitHub - alibaba/easyexcel: 快速、简洁、解决大文件内存溢出的java处理Excel工具
首先在service_cmn的pom文件下引入依赖:
演示一下,创建实体类:
UserData:和:
package com.atguigu.easyexcel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data //lombok插件注解生成getset方法
public class UserData {
@ExcelProperty("用户编号") //表格标题注解
private int uid;
@ExcelProperty("用户名称")
private String username;
}
TestWrite:
package com.atguigu.easyexcel;
import com.alibaba.excel.EasyExcel;
import java.util.ArrayList;
import java.util.List;
public class TestWrite {
public static void main(String[] args) {
//设置excel文件的路径和文件名称
String filename="E:\\excel\\01.xlsx";//路径
//构建数据的list集合
List<UserData> list=new ArrayList();
for (int i=0;i<10;i++){
UserData data=new UserData();
data.setUid(i);
data.setUsername("Lucy"+i);
list.add(data);
}
//调用方法实现写操作
EasyExcel.write(filename,UserData.class).sheet("用户信息")
.doWrite(list);
}
}
E盘创建一个文件夹excel:
运行:
目录下多了一个文件:
打开文件:
(2)EasyExcel-读操作
写一个实体类:
UserData:
package com.atguigu.easyexcel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data //lombok插件注解生成getset方法
public class UserData {
@ExcelProperty(value = "用户编号",index = 0) //表格标题注解
private int uid;
@ExcelProperty(value = "用户名称",index = 1)
private String username;
}
创建一个监听器,实现一行一行的读:
ExcelListener:
package com.atguigu.easyexcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.Map;
public class ExcelListener extends AnalysisEventListener<UserData> {
//一行一行的读取excel内容,从第二行读取
@Override
public void invoke(UserData userData, AnalysisContext analysisContext) {
System.out.println(userData);
}
//读取表头内容
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
System.out.println("表头信息"+headMap);
}
//读取之后执行
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
TestRead:
package com.atguigu.easyexcel;
import com.alibaba.excel.EasyExcel;
public class TestRead {
public static void main(String[] args) {
//读取文件的路径
String filename="E:\\excel\\01.xlsx";//路径
//调用方法实现读取操作
EasyExcel.read(filename,UserData.class,new ExcelListener()).sheet().doRead();
}
}
运行:
(3)后台系统-数据字典-导出
把下面的数据写入到一个excel表中去:
在DicController中添加接口:方法:
//导出数据字典接口
@GetMapping("exportData")
public void exportDict(HttpServletResponse response) {
dictService.exportDictData(response);
}
DicService:接口:
写这个方法:
package com.atguigu.yygh.cmn.service;
import com.atguigu.yygh.model.cmn.Dict;
import com.baomidou.mybatisplus.extension.service.IService;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface DictService extends IService<Dict> {
//根据数据id查询子数据列表
List<Dict> findChlidData(Long id);
//导出数据字典接口
void exportDictData(HttpServletResponse response);
}
实现类:DictServiceImpl:
//导出数据字典接口
@Override
public void exportDictData(HttpServletResponse response) {
//设置下载
response.setContentType("application/vnd.ms-excel");//设置类型
response.setCharacterEncoding("utf-8");//设置编码
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = "dict";//名字
response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");//头信息,以下载方式打开
//查询数据库
List<Dict> dictList = baseMapper.selectList(null);
//将Dict转--DictEeVo
List<DictEeVo> dictEeVoList=new ArrayList<>();
for (Dict dict:dictList){
DictEeVo dictEeVo=new DictEeVo();
//dictEeVo.setId(dict.getId());用下面替换
BeanUtils.copyProperties(dict,dictEeVo);
dictEeVoList.add(dictEeVo);//放入集合
}
//调用方法进行写操作
try {
EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("dict").doWrite(dictEeVoList);
} catch (IOException e) {
e.printStackTrace();
}
}
实体类我们原来创建好了:
package com.atguigu.yygh.vo.cmn;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* <p>
* Dict
* </p>
*
* @author qy
*/
@Data
public class DictEeVo {
@ExcelProperty(value = "id" ,index = 0)
private Long id;
@ExcelProperty(value = "上级id" ,index = 1)
private Long parentId;
@ExcelProperty(value = "名称" ,index = 2)
private String name;
@ExcelProperty(value = "值" ,index = 3)
private String value;
@ExcelProperty(value = "编码" ,index = 4)
private String dictCode;
}
前端:
在dict-list.vue:
加导出按钮:
点击导出:
(4) 后台系统-数据字典-导入
在DictController中添加接口方法:
package com.atguigu.yygh.cmn.controller;
import com.atguigu.yygh.cmn.service.DictService;
import com.atguigu.yygh.common.result.Result;
import com.atguigu.yygh.model.cmn.Dict;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Api(tags = "数据字典接口") //swagger中的提示注解
@RestController
@RequestMapping("/admin/cmn/dict")
@CrossOrigin //跨域访问注解
public class DictController {
@Autowired
private DictService dictService;
//根据数据id查询子数据列表
@ApiOperation(value = "根据数据id查询子数据列表")
@GetMapping("findChildData/{id}")
public Result findChildData(@PathVariable Long id) {
List<Dict> list = dictService.findChlidData(id);
return Result.ok(list);
}
//导出数据字典接口
@GetMapping("exportData")
public void exportDict(HttpServletResponse response) {
dictService.exportDictData(response);
}
//导入数据字典
@PostMapping("importData")
public Result importDict(MultipartFile file) {
dictService.importDictData(file);
return Result.ok();
}
}
DictService:接口添加这个方法:
package com.atguigu.yygh.cmn.service;
import com.atguigu.yygh.model.cmn.Dict;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface DictService extends IService<Dict> {
//根据数据id查询子数据列表
List<Dict> findChlidData(Long id);
//导出数据字典接口
void exportDictData(HttpServletResponse response);
//导入数据字典
void importDictData(MultipartFile file);
}
DictServiceImpl:实现类:实现这个方法:
package com.atguigu.yygh.cmn.service.impl;
import com.alibaba.excel.EasyExcel;
import com.atguigu.yygh.cmn.listener.DictListener;
import com.atguigu.yygh.cmn.mapper.DictMapper;
import com.atguigu.yygh.cmn.service.DictService;
import com.atguigu.yygh.model.cmn.Dict;
import com.atguigu.yygh.vo.cmn.DictEeVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {
//根据数据id查询子数据列表
@Override
public List<Dict> findChlidData(Long id) {
QueryWrapper<Dict> wrapper=new QueryWrapper<>();
wrapper.eq("parent_id",id);
List<Dict> dictList = baseMapper.selectList(wrapper);
//向dictList集合中的每个Dict对象设置hasChildren属性
for (Dict dict:dictList){
Long dictId = dict.getId();
boolean ischild = this.isChildren(dictId);//调用下面方法获取是否有子节点
dict.setHasChildren(ischild);//设置属性
}
return dictList;
}
//导出数据字典接口
@Override
public void exportDictData(HttpServletResponse response) {
//设置下载
response.setContentType("application/vnd.ms-excel");//设置类型
response.setCharacterEncoding("utf-8");//设置编码
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = "dict";//名字
response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");//头信息,以下载方式打开
//查询数据库
List<Dict> dictList = baseMapper.selectList(null);
//将Dict转--DictEeVo
List<DictEeVo> dictEeVoList=new ArrayList<>();
for (Dict dict:dictList){
DictEeVo dictEeVo=new DictEeVo();
//dictEeVo.setId(dict.getId());用下面替换
BeanUtils.copyProperties(dict,dictEeVo);
dictEeVoList.add(dictEeVo);//放入集合
}
//调用方法进行写操作
try {
EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("dict").doWrite(dictEeVoList);
} catch (IOException e) {
e.printStackTrace();
}
}
//导入数据字典
@Override
public void importDictData(MultipartFile file) {
try {
EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper)).sheet().doRead();
} catch (IOException e) {
e.printStackTrace();
}
}
//判断id下面是否有字节点
private boolean isChildren(Long id){
QueryWrapper<Dict> wrapper=new QueryWrapper<>();
wrapper.eq("parent_id",id);
Integer count = baseMapper.selectCount(wrapper);
return count>0;
}
}
创建监听器:
DictListener:
package com.atguigu.yygh.cmn.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.atguigu.yygh.cmn.mapper.DictMapper;
import com.atguigu.yygh.model.cmn.Dict;
import com.atguigu.yygh.vo.cmn.DictEeVo;
import org.springframework.beans.BeanUtils;
public class DictListener extends AnalysisEventListener<DictEeVo> {
//引入dictMapper
private DictMapper dictMapper;
public DictListener(DictMapper dictMapper) {
this.dictMapper = dictMapper;
}
//一行一行的读取excel内容,从第二行读取
@Override
public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
//调用方法添加数据库
//将dictEeVo转换为Dict
Dict dict=new Dict();
//使用工具类转换
BeanUtils.copyProperties(dictEeVo,dict);
dictMapper.insert(dict);
}
//读取之后执行
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
前端:
在list.vue中加按钮:
添加导入弹出框:
<template>
<div class="app-container">
<!-- 导出按钮 -->
<div class="el-toolbar">
<div class="el-toolbar-body" style="justify-content: flex-start;">
<a href="http://localhost:8202/admin/cmn/dict/exportData" target="_blank">
<el-button type="text" @click="exportData"><i class="fa fa-plus"/> 导出</el-button>
</a>
<!-- 导入按钮 -->
<el-button type="text" @click="importData"><i class="fa fa-plus"/> 导入</el-button>
</div>
</div>
<el-table
:data="list"
:load="getChildrens"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
style="width: 100%"
row-key="id"
border
lazy >
<el-table-column label="名称" width="230" align="left">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="编码" width="220">
<template slot-scope="{row}">
{{ row.dictCode }}
</template>
</el-table-column>
<el-table-column label="值" width="230" align="left">
<template slot-scope="scope">
<span>{{ scope.row.value }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center">
<template slot-scope="scope">
<span>{{ scope.row.createTime }}</span>
</template>
</el-table-column>
</el-table>
<!-- 导入弹出框 -->
<el-dialog title="导入" :visible.sync="dialogImportVisible" width="480px">
<el-form label-position="right" label-width="170px">
<el-form-item label="文件">
<el-upload
:multiple="false"
:on-success="onUploadSuccess"
:action="'http://localhost:8202/admin/cmn/dict/importData'"
class="upload-demo">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传excel.xls文件,且不超过500kb</div>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogImportVisible = false">
取消
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
//引入接口定义的js文件
import dict from '@/api/dict'
export default {
data() {//定义变量和初始值
return {
list: [],//数据字典列表数组
dialogImportVisible:false,//设置弹框是否弹出
}
},
created() {//页面初始化之前执行
this.getDictList(1)
},
methods: {//具体的方法
getDictList(id) {
dict.dictList(id)
.then(response => {
this.list=response.data //往数组里赋值
})
},
//查询层级的方法
getChildrens(tree, treeNode, resolve) {
//第一级下面的查询
dict.dictList(tree.id).then(response => {
resolve(response.data)
})
},
//导出数据字典
exportData() {
//调用导出接口
window.location.href="http://localhost:8202/admin/cmn/dict/exportData"
},
//导入数据字典方法
importData() {
this.dialogImportVisible = true //显示弹出框
},
//上传成功调用方法,
onUploadSuccess(response, file) {
this.$message.info('上传成功')
//关闭弹框
this.dialogImportVisible = false
//刷新页面
this.getDictList(1)
},
}
}
</script>
点击导入:
提前准备好:excel数据