目录
- 一、数据字典介绍
- 1、什么是数据字典
- 2、页面展示效果
- 3、数据字典表设计
- 4、数据分析
- 5、根据页面效果分析数据接口
- 二、搭建数据字典模块
- 三、数据字典列表接口
- 1、model模块添加数据字典实体
- 2、添加数据字典mapper
- 3、添加数据字典service
- 4、添加数据字典controller
- 四、数据字典列表前端
- 1、添加数据字典路由
- 2、定义数据字典列表接口
- 3、在dict/list.vue调用
- 4、页面数据渲染
- 五、EasyExcel
- 1、EasyExcel介绍
- 2、EasyExcel特点
- 六、EasyExcel写操作
- 1、在service_cmn模块的pom中引入xml相关依赖
- 2、创建实体类
- 3 、实现写操作
- 七、EasyExcel读操作
- 1、创建实体类
- 2、创建读取操作的监听器
- 3、调用实现最终的读取
- 4、同时解析excel文件中多个sheet
- 八、数据字典导出功能(前后端)
- 1、查看model实体类
- 2、在DictService添加方法和实现
- 3、添加Controller方法
- 4、数据字典导出前端
- 九、数据字典导入功能(前后端)
- 1、创建读取监听器
- 2、添加controller方法
- 3、添加service方法
- 4、数据字典导入前端
一、数据字典介绍
1、什么是数据字典
数据字典就是管理系统常用的分类数据或者一些固定数据,例如:省市区三级联动数据、民族数据、行业数据、学历数据等,由于该系统大量使用这种数据,所以我们要做一个数据管理方便管理系统数据,一般系统基本都会做数据管理。
2、页面展示效果
3、数据字典表设计
4、数据分析
parent_id:
上级id,通过id与parent_id构建上下级关系,例如:我们要获取所有行业数据,那么只需要查询parent_id=20000的数据
name: 名称,例如:填写用户信息,我们要select标签选择民族,“汉族”就是数据字典的名称
value: 值,例如:填写用户信息,我们要select标签选择民族,“1”(汉族的标识)就是数据字典的值
dict_code: 编码,编码是我们自定义的,全局唯一,例如:我们要获取行业数据,我们可以通过parent_id获取,但是parent_id是不确定的,所以我们可以根据编码来获取行业数据
说明:系统中会使用省市区三级联动数据,该数据我们来自“国家统计局”官方数据,地址:http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/index.html
5、根据页面效果分析数据接口
数据字典是树形展示,由于数据众多,我们使用“树形数据与懒加载”的方式展现数据列表,其他就是对数据的新增、修改与删除操作,因此需要提供的接口如下:
1,根据上级id获取下级数据(构造树形数据),参考文档:https://element.eleme.cn/#/zh-CN/component/table,页面搜索:树形数据与懒加载
2,导入接口
3,导出接口
二、搭建数据字典模块
1、创建service_cmn模块
2、创建application.properties配置文件
# 服务端口
server.port=8202
# 服务名
spring.application.name=service-cmn
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/yygh_cmn?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3、使用代码生成器生成mapper接口,service,controller层,entity层生成之后删除!
代码生成器从yygh_hosp模块的拷贝[同时注意拷贝代码生成器的两个依赖哦]
4.创建启动类
@SpringBootApplication
@ComponentScan(basePackages = {"com.donglin"})
@MapperScan("com.donglin.yygh.cmn.mapper")
public class ServiceCmnApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceCmnApplication.class,args);
}
}
5.配置nginx反向代理并重启
三、数据字典列表接口
根据element组件要求,返回列表数据必须包含hasChildren字典,如图:
https://element.eleme.cn/#/zh-CN/component/table
1、model模块添加数据字典实体
@Data
@ApiModel(description = "数据字典")
@TableName("dict")
public class Dict {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private Date createTime;
@ApiModelProperty(value = "更新时间")
@TableField("update_time")
private Date updateTime;
@ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")
@TableLogic
@TableField("is_deleted")
private Integer isDeleted;
@ApiModelProperty(value = "上级id")
@TableField("parent_id")
private Long parentId;
@ApiModelProperty(value = "名称")
@TableField("name")
private String name;
@ApiModelProperty(value = "值")
@TableField("value")
private String value;
@ApiModelProperty(value = "编码")
@TableField("dict_code")
private String dictCode;
@ApiModelProperty(value = "其他参数")
@TableField(exist = false)
private Map<String,Object> param = new HashMap<>();
@ApiModelProperty(value = "是否包含子节点")
@TableField(exist = false)
private boolean hasChildren;
}
说明:hasChildren为树形组件所需字典,标识为数据库表不存在该字段
2、添加数据字典mapper
public interface DictMapper extends BaseMapper<Dict> {
}
3、添加数据字典service
public interface DictService extends IService<Dict> {
//根据数据id查询子数据列表
List<Dict> getchildListById(Long pid);
}
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {
//根据数据id查询子数据列表
@Override
public List<Dict> getchildListById(Long pid) {
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id",pid);
List<Dict> dictList = baseMapper.selectList(wrapper);
//向list集合每个dict对象中设置hasChildren
for (Dict dict : dictList) {
Long dictId = dict.getId();
boolean isChild = this.isChildren(dictId);
dict.setHasChildren(isChild);
}
return dictList;
}
//判断id下面是否有子节点
private boolean isChildren(Long dictId) {
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id",dictId);
Integer count = baseMapper.selectCount(wrapper);
return count>0;
}
}
4、添加数据字典controller
@Api(tags = "数据字典接口")
@RestController
@RequestMapping("/admin/cmn")
@CrossOrigin
public class DictController {
@Autowired
private DictService dictService;
@ApiOperation(value = "根据数据id查询子数据列表")
@GetMapping("/childList/{pid}")
public R getchildListById(@PathVariable Long pid){
List<Dict> list = dictService.getchildListById(pid);
return R.ok().data("items",list);
}
}
四、数据字典列表前端
1、添加数据字典路由
修改router/index.js文件
{
path: '/yygh/cmn',
component: Layout,
redirect: '/yygh/cmn/list',
name: '字典信息管理',
alwaysShow: true,
meta: { title: '字典信息管理', icon: 'el-icon-s-help' },
children: [
{
path: 'list',
name: '字典信息展示',
component: () => import('@/views/yygh/cmn/list'),
meta: { title: '字典信息展示', icon: 'table' }
}
]
},
2、定义数据字典列表接口
创建文件 src/api/yygh/dict.js
import request from '@/utils/request'
const API = '/admin/cmn'
export default{
getDictList(pid) {
return request({
url: `${API}/childList/${pid}`,
method: 'get'
})
},
}
3、在dict/list.vue调用
<script>
import dict from '@/api/dict.js'
export default{
data(){
return{
list:[]
}
},
methods:{
//row:当前行数据
//resolve:是一个函数,作用是将当前元素的子元素挂载到当前元素下边
load(row, treeNode, resolve){
dict.getDictList(row.id).then(res=>{
resolve(res.data.items)
})
}
},
created(){
dict.getDictList(1).then(res=>{
this.list = res.data.items
})
}
}
</script>
4、页面数据渲染
修改dict/list.vue页面
<template>
<div class="app-container">
<el-table
:data="list"
style="width: 100%"
row-key="id"
border
lazy
:load="load"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="name"
label="名称"
width="180">
</el-table-column>
<el-table-column
prop="dictCode"
label="编码"
width="180">
</el-table-column>
<el-table-column
prop="value"
label="值"
width="180">
</el-table-column>
<el-table-column
prop="createTime"
label="创建时间">
</el-table-column>
</el-table>
</div>
</template>
五、EasyExcel
1、EasyExcel介绍
1、数据导入:减轻录入工作量
2、数据导出:统计信息归档
3、数据传输:异构系统之间数据传输
2、EasyExcel特点
- Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
- EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
- EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
文档地址:https://alibaba-easyexcel.github.io/index.html
github地址:https://github.com/alibaba/easyexcel
1 导出示例
示例链接:https://alibaba-easyexcel.github.io/quickstart/write.html
2 导入示例
示例链接:https://alibaba-easyexcel.github.io/quickstart/read.html
3 EasyExcel集成
在service_cmn模块添加依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
六、EasyExcel写操作
1、在service_cmn模块的pom中引入xml相关依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
2、创建实体类
@Data
public class Stu {
//设置表头名称
@ExcelProperty("学生编号")
private int sno;
//设置表头名称
@ExcelProperty("学生姓名")
private String sname;
}
3 、实现写操作
(1)创建方法循环设置要添加到Excel的数据
//循环设置要添加的数据,最终封装到list集合中
private static List<Stu> data() {
List<Stu> list = new ArrayList<Stu>();
for (int i = 0; i < 10; i++) {
Stu data = new Stu();
data.setSno(i);
data.setSname("张三"+i);
list.add(data);
}
return list;
}
(2)实现最终的添加操作(写法一)
public static void main(String[] args) throws Exception {
// 写法1
String fileName = "F:\\hosptial project\\11.xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, Stu.class).sheet("写入方法一").doWrite(data());
}
(3)实现最终的添加操作(写法二)
public static void main(String[] args) throws Exception {
// 写法2,方法二需要手动关闭流
String fileName = "F:\\hosptial project\\11.xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, Stu.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("写入方法二").build();
excelWriter.write(data(), writeSheet);
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
七、EasyExcel读操作
1、创建实体类
@Data
public class Stu {
//设置表头名称
//设置列对应的属性
@ExcelProperty(value = "学生编号",index = 0)
private int sno;
//设置表头名称
//设置列对应的属性
@ExcelProperty(value = "学生姓名",index = 1)
private String sname;
}
2、创建读取操作的监听器
public class ExcelListener extends AnalysisEventListener<Stu> {
//创建list集合封装最终的数据
List<Stu> list = new ArrayList<Stu>();
//一行一行去读取excle内容
@Override
public void invoke(Stu user, AnalysisContext analysisContext) {
System.out.println("***"+user);
list.add(user);
}
//读取excel表头信息
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
System.out.println("表头信息:"+headMap);
}
//读取完成后执行
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
3、调用实现最终的读取
public static void main(String[] args) throws Exception {
String fileName = "F:\\hosptial project\\11.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, Stu.class, new ExcelListener()).sheet().doRead();
}
4、同时解析excel文件中多个sheet
ExcelReader excelReader = EasyExcel.read("F:\\hosptial project\\11.xlsx").build();
ReadSheet sheet1 = EasyExcel.readSheet(0).head(Stu.class).registerReadListener(new ExcelListener()).build();
ReadSheet sheet2 = EasyExcel.readSheet(1).head(Stu.class).registerReadListener(new ExcelListener()).build();
excelReader.read(sheet1,sheet2);
excelReader.finish();
八、数据字典导出功能(前后端)
1、查看model实体类
在model模块查看实体:com.donglin.yygh.vo.cmn.DictEeVo
@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;
}
2、在DictService添加方法和实现
public interface DictService extends IService<Dict> {
void download(HttpServletResponse response);
}
@Override
public void download(HttpServletResponse response) throws IOException {
List<Dict> dictList = baseMapper.selectList(null);
ArrayList<DictEeVo> dictEeVoList = new ArrayList<>(dictList.size());
for (Dict dict : dictList) {
DictEeVo dictEeVo = new DictEeVo();
BeanUtils.copyProperties(dict,dictEeVo);
dictEeVoList.add(dictEeVo);
}
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("数据字典", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("模板").doWrite(dictEeVoList);
}
3、添加Controller方法
@ApiOperation(value="导出")
@GetMapping(value = "/download")
public void download(HttpServletResponse response){
dictService.download(response);
}
4、数据字典导出前端
list.vue页面添加导出按钮
<div class="el-toolbar">
<div class="el-toolbar-body" style="justify-content: flex-start;">
<el-button type="text" @click="exportData"><i class="fa fa-plus"/> 导出</el-button>
</div>
</div>
编写调用方法
exportData(){
window.open("http://localhost:9001/admin/cmn/download")
},
九、数据字典导入功能(前后端)
1、创建读取监听器
public class DictListener extends AnalysisEventListener<DictEeVo> {
//不交给spring容器@Component 我们使用构造器来实现@Autowire
private DictMapper dictMapper;
public DictListener(DictMapper dictMapper){
this.dictMapper = dictMapper;
}
@Override
public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
Dict dict = new Dict();
BeanUtils.copyProperties(dictEeVo,dict);
QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id",dictEeVo.getId());
Integer count = this.dictMapper.selectCount(queryWrapper);
if (count>0){
this.dictMapper.updateById(dict);
}else {
this.dictMapper.insert(dict);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
2、添加controller方法
@ApiOperation(value = "导入")
@PostMapping("/upload")
public R upload(MultipartFile file) throws IOException {
dictService.uploadFile(file);
return R.ok();
}
3、添加service方法
@Autowired
private DictListener dictListener;
public void uploadFile(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper)).sheet(0).doRead();
}
4、数据字典导入前端
1、在list.vue页面添加导入按钮
<el-button type="text" @click="importData"><i class="fa fa-plus"/> 导入</el-button>
2、添加导入弹出层
<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:9001/admin/cmnt/upload'"
class="upload-demo">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传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>
3、编写调用方法
data(){
return{
list:[],
dialogImportVisible:false
}
},
methods:{
onUploadSuccess(){
this.$message.success("上传成功")
dict.getDictList(1).then(res=>{
this.list = res.data.items
})
this.dialogImportVisible=false
},
importData(){
this.dialogImportVisible=true
},
}